Python 实战:如何给你的程序添加授权码机制_使用软件,作者要mac地址后给授权-程序员宅基地

技术标签: python  授权码  编程语言  

大家好,我是机灵鹤。

前几天有个粉丝问我说,他写了一个蛮有意思的小程序,准备在网上发布,但是又担心程序在不受控制的情况下传播。想问我有没有办法整一个授权码机制,只有输入授权码才能使用软件,授权码过期或者更换机器都需要重新授权。

真是蛮有意思又非常实用的一个小需求,以后如果想要分享自己的程序但又不希望自己的程序被随意传播的,都可以用得上。

这里给大家简单分享一下我的实现方法,感兴趣的同学可以学起来。

如果你有其它比较好的思路,也欢迎跟我一起交流。


一、总体思路

软件授权方案大概分成两个部分:程序本体注册机

当用户启动程序时,程序会检验本地的 授权文件 是否合法,若验证通过,则直接进入程序,若未找到授权文件或者授权文件校验失败,则进入重新授权流程。进入授权流程时,程序先扫描本机运行环境,生成 机器码 ,然后提示用户找管理员获取授权码;用户将机器码发送给管理员,管理员将机器码输入 注册机 中,生成与该机器码唯一绑定的 授权码 后,发送给用户;用户在程序中输入授权码,验证通过后正式进入程序,并在本地生成授权文件。

下面是我的软件授权方案的流程图。

授权流程图

以上便是我这套软件授权方案的总体思路,接下来,我会教大家如何用 python 来实现它。

二、实现过程

实现这套授权机制,我们需要解决以下几个小问题。

  1. 如何使授权码与机器唯一绑定,仅在本台机器上有效?
  2. 如何生成验证码,以及如何验证授权码是否有效?
  3. 如何保护自己的授权码不那么容易被人破解?

带着这些问题,我们继续往下看。

2.1 获取机器信息

要回答第一个问题,首先要搞明白,软件如何判断自己运行在哪一台机器上?

我们知道,每一台机器都会有一个唯一 Mac 地址,我们可以用它来作为机器的唯一标识。

此外为了保险,我们还可以获取机器的 CPU 序列号硬盘序列号主板序列号 等等数据,与 Mac 地址 共同作为一台机器的唯一标识。

windows 系统下,我们可以使用 wmi 的库来获取机器的硬件信息。

没有安装 wmi 库的,可以运行下面的命令行来安装。

pip install wmi
2.1.1 获取 CPU 序列号
import wmi

m_wmi = wmi.WMI()
cpu_info = m_wmi.Win32_Processor()
if len(cpu_info) > 0:
	serial_number = cpu_info[0].ProcessorId
    print(serial_number)
2.1.2 获取 MAC 地址
import wmi

m_wmi = wmi.WMI()
for network in m_wmi.Win32_NetworkAdapterConfiguration():
    mac_address = network.MacAddress
    if mac_address != None:
        print(mac_address)
2.1.3 获取硬盘序列号
import wmi

m_wmi = wmi.WMI()
disk_info = m_wmi.Win32_PhysicalMedia()
if len(disk_info) > 0:
    serial_number = disk_info[0].SerialNumber.strip()
    print(serial_number)
2.1.4 获取主板序列号
import wmi

m_wmi = wmi.WMI()
board_info = self.m_wmi.Win32_BaseBoard()
if len(board_info) > 0:
    board_id = board_info[0].SerialNumber.strip().strip('.')
    print(board_id)

2.2 生成机器码

使用上述方法,我们可以获取到机器的 CPU 序列号硬盘序列号主板序列号Mac 地址 信息,通过这些信息,我们便可以生成唯一标识一台机器的 机器码

理论上,我们将这些数据直接进行字符串拼接,便可作为机器码使用,但是实际上,这样做存在一些问题。

  1. 机器码过长,使用体验不太友好。
  2. 直接暴露机器的硬件数据,有信息安全隐患。

所以我们需要对机器的这些硬件数据进行一些处理,生成一个长度适中的,既可以作为机器的唯一标识,又不会暴露机器硬件数据的机器码。

# 获取机器的 Mac地址、CPU序列号、硬盘序列号、主板序列号
mac_address = get_mac_address()
cpu_serial = get_cpu_serial()
disk_serial = get_disk_serial()
board_serial = get_board_serial()

# 将机器的硬件数据字符串拼接
combine_str =  mac_address + cpu_serial + disk_serial + board_serial
combine_byte = combine_str.encode("utf-8")

# 进行 MD5 编码
machine_code = hashlib.md5(combine_byte).hexdigest()
print(machine_code.upper())

众所周知,MD5 是一种常用的不可逆的数据加密算法,我们用它对机器硬件数据进行加密,一方面它加密后的结果长度固定(32个字符),另一方面也可以在一定程度上保护数据安全。

2.3 授权验证逻辑

想要在离线的情况下实现 授权码机器码 唯一绑定,意味着授权码是由机器码经过一系列复杂的加密算法处理后得到的。

授权码验证的逻辑也比较简单,大概有三种思路:

  1. 将机器码使用相同的加密算法处理,得到的结果与验证码进行比较。
  2. 将验证码使用对应的解密算法处理,得到的结果与机器码进行比较。
  3. 使用特定的算法分别处理机器码和授权码,将得到的结果进行比较。

一般来讲,第一种思路实现起来会比较简单一些,因为它只需要写一套加密算法即可(软件验证部分跟授权码生成部分用的是同一套加密算法),而且无需考虑解密的问题,安全性会更高(因为可以使用不可逆的加密算法)

大概的验证逻辑如下:

# 获取机器码
machine_code = getMachineCode()
# 自己定义 Encrypted 函数进行加密处理
encrypt_code = Encrypted(machine_code.encode("utf-8"))

# 读取本地的授权文件
if os.path.exists("register.bin"):
    with open("register.bin", "r") as f:
        key_code = f.read()
        # 如果机器码经过加密后的值,等于授权码的值,则验证通过,否则验证失败
        if key_code == encrypt_code:
            print("验证通过")
        else:
            print("验证失败")
else:
    print("验证失败")

2.3 生成授权码

如何将机器码加密生成授权码,可以使用的加密算法其实五花八门,每个人都可以自己研究一套自己独有的加密方法,尤其是不需要考虑解密,不要求算法可逆的情况下,问题就更简单了。

比如:

  • 你可以提取机器码的奇数位或偶数位,或者自己定义的任意位置的字符出来,组合成授权码。
  • 可以将指定位置的字符进行交换,得到的字符串作为授权码。
  • 可以将其中的某些字符替换成其它字符,得到的字符串作为授权码。
  • 甚至可以直接再进行一次 MD5 加密,结果作为授权码。

总之,方法是非常多样化的,只要你生成的授权码可以正常使用,并且没那么容易让别人猜出你授权码生成的规律即可。

作为示例,我演示一下我 Demo 中的加密方法。

import base64
import hashlib
from pyDes import *

def Encrypted(self, code):
	# 使用 DES-CBC加密算法加密机器码
    Des_key = "posdvsgt" 				#自定义 Key,需八位
    Des_IV = "\x11\2\x2a\3\1\x27\2\0"  	# 自定IV向量
    k = des(Des_key, CBC, Des_IV, pad=None, padmode=PAD_PKCS5)
    EncryptStr = k.encrypt(code)
    # 加密结果转 base64 编码
    base64_code = base64.b32encode(EncryptStr)
	# 编码结果使用 MD5 加密
    md5_code = hashlib.md5(base64_code).hexdigest().upper()
    return md5_code

通过上述加密算法,我们可以通过机器码生成授权码,并且通过一系列加密算法的组合加密,基本上很难观察出机器码和授权码之间的关系,更没办法推算出你具体用了什么加密方法。

需要说明的是,

不管使用什么算法,凡离线方式的加密必然是可以被破解的,只是破解的时间和成本问题,所以上述的加密只是提高了破解门槛,防小白不防大神。

想要万无一失,还得是在线授权验证。

2.5 打包测试

核心算法搞定以后,整理一下代码就可以打包测试了。


可以使用 pyinstaller 库来把代码打包成 .exe 程序。

没有安装 pyinstaller 库的,可以运行下面的命令行来安装。

pip install pyinstaller

使用 pyinstaller 库打包的命令如下:

pyinstaller -F xxx.py

打包完成以后,会在当前目录下的 dist 文件夹中,生成 xxx.exe 可执行程序。


首次启动程序时(无授权文件),会提示输入激活码,即授权码。

随便输入错误的授权码,会验证失败,提示重新输入。

image-20221110185635873

此时我们启动注册机,根据提示复制机器码 BD1F7DF8646CD3A101C3DA8610672ED1 到注册机中,生成激活码。

image-20221110190013275

复制并输入激活码,此时授权验证成功,程序可以正常使用,输出了 Hello World! 字样。

image-20221110190611432

后续再次启动程序时,由于已有授权文件,所以可以直接进入。

image-20221111100332284

2.6 源码分享

为了方便大家学习交流,我将代码整理打包上传,并附上了一个 Demo 程序。

关注公众号 机灵鹤 并回复文字 授权码 ,即可获取。

感兴趣的同学可以自行下载,大家一起交流学习。

四、改进措施

当然,作为 V1.0 版本的授权码机制,其实还是有很多值得改进的地方,比如:

  • 设置授权有效期,过期则需要重新授权

  • 授权方式改成在线,安全性更高的同时也可以进行更加精细化的授权管理。

  • 授权后台管理系统,更加方便地管理自己的软件授权。

如果后续大家有需求,我也有精力的话,可以把它做的更加完善一些。


如果文章中有哪里没有讲明白,或者讲解有误的地方,欢迎在评论区批评指正,大家一起学习交流,共同进步。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wenxuhonghe/article/details/127880072

智能推荐

Docker 快速上手学习入门教程_docker菜鸟教程-程序员宅基地

文章浏览阅读2.5w次,点赞6次,收藏50次。官方解释是,docker 容器是机器上的沙盒进程,它与主机上的所有其他进程隔离。所以容器只是操作系统中被隔离开来的一个进程,所谓的容器化,其实也只是对操作系统进行欺骗的一种语法糖。_docker菜鸟教程

电脑技巧:Windows系统原版纯净软件必备的两个网站_msdn我告诉你-程序员宅基地

文章浏览阅读5.7k次,点赞3次,收藏14次。该如何避免的,今天小编给大家推荐两个下载Windows系统官方软件的资源网站,可以杜绝软件捆绑等行为。该站提供了丰富的Windows官方技术资源,比较重要的有MSDN技术资源文档库、官方工具和资源、应用程序、开发人员工具(Visual Studio 、SQLServer等等)、系统镜像、设计人员工具等。总的来说,这两个都是非常优秀的Windows系统镜像资源站,提供了丰富的Windows系统镜像资源,并且保证了资源的纯净和安全性,有需要的朋友可以去了解一下。这个非常实用的资源网站的创建者是国内的一个网友。_msdn我告诉你

vue2封装对话框el-dialog组件_<el-dialog 封装成组件 vue2-程序员宅基地

文章浏览阅读1.2k次。vue2封装对话框el-dialog组件_

MFC 文本框换行_c++ mfc同一框内输入二行怎么换行-程序员宅基地

文章浏览阅读4.7k次,点赞5次,收藏6次。MFC 文本框换行 标签: it mfc 文本框1.将Multiline属性设置为True2.换行是使用"\r\n" (宽字符串为L"\r\n")3.如果需要编辑并且按Enter键换行,还要将 Want Return 设置为 True4.如果需要垂直滚动条的话将Vertical Scroll属性设置为True,需要水平滚动条的话将Horizontal Scroll属性设_c++ mfc同一框内输入二行怎么换行

redis-desktop-manager无法连接redis-server的解决方法_redis-server doesn't support auth command or ismis-程序员宅基地

文章浏览阅读832次。检查Linux是否是否开启所需端口,默认为6379,若未打开,将其开启:以root用户执行iptables -I INPUT -p tcp --dport 6379 -j ACCEPT如果还是未能解决,修改redis.conf,修改主机地址:bind 192.168.85.**;然后使用该配置文件,重新启动Redis服务./redis-server redis.conf..._redis-server doesn't support auth command or ismisconfigured. try

实验四 数据选择器及其应用-程序员宅基地

文章浏览阅读4.9k次。济大数电实验报告_数据选择器及其应用

随便推点

灰色预测模型matlab_MATLAB实战|基于灰色预测河南省社会消费品零售总额预测-程序员宅基地

文章浏览阅读236次。1研究内容消费在生产中占据十分重要的地位,是生产的最终目的和动力,是保持省内经济稳定快速发展的核心要素。预测河南省社会消费品零售总额,是进行宏观经济调控和消费体制改变创新的基础,是河南省内人民对美好的全面和谐社会的追求的要求,保持河南省经济稳定和可持续发展具有重要意义。本文建立灰色预测模型,利用MATLAB软件,预测出2019年~2023年河南省社会消费品零售总额预测值分别为21881...._灰色预测模型用什么软件

log4qt-程序员宅基地

文章浏览阅读1.2k次。12.4-在Qt中使用Log4Qt输出Log文件,看这一篇就足够了一、为啥要使用第三方Log库,而不用平台自带的Log库二、Log4j系列库的功能介绍与基本概念三、Log4Qt库的基本介绍四、将Log4qt组装成为一个单独模块五、使用配置文件的方式配置Log4Qt六、使用代码的方式配置Log4Qt七、在Qt工程中引入Log4Qt库模块的方法八、获取示例中的源代码一、为啥要使用第三方Log库,而不用平台自带的Log库首先要说明的是,在平时开发和调试中开发平台自带的“打印输出”已经足够了。但_log4qt

100种思维模型之全局观思维模型-67_计算机中对于全局观的-程序员宅基地

文章浏览阅读786次。全局观思维模型,一个教我们由点到线,由线到面,再由面到体,不断的放大格局去思考问题的思维模型。_计算机中对于全局观的

线程间控制之CountDownLatch和CyclicBarrier使用介绍_countdownluach于cyclicbarrier的用法-程序员宅基地

文章浏览阅读330次。一、CountDownLatch介绍CountDownLatch采用减法计算;是一个同步辅助工具类和CyclicBarrier类功能类似,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。二、CountDownLatch俩种应用场景: 场景一:所有线程在等待开始信号(startSignal.await()),主流程发出开始信号通知,既执行startSignal.countDown()方法后;所有线程才开始执行;每个线程执行完发出做完信号,既执行do..._countdownluach于cyclicbarrier的用法

自动化监控系统Prometheus&Grafana_-自动化监控系统prometheus&grafana实战-程序员宅基地

文章浏览阅读508次。Prometheus 算是一个全能型选手,原生支持容器监控,当然监控传统应用也不是吃干饭的,所以就是容器和非容器他都支持,所有的监控系统都具备这个流程,_-自动化监控系统prometheus&grafana实战

React 组件封装之 Search 搜索_react search-程序员宅基地

文章浏览阅读4.7k次。输入关键字,可以通过键盘的搜索按钮完成搜索功能。_react search