大家好,我是机灵鹤。
前几天有个粉丝问我说,他写了一个蛮有意思的小程序,准备在网上发布,但是又担心程序在不受控制的情况下传播。想问我有没有办法整一个授权码机制,只有输入授权码才能使用软件,授权码过期或者更换机器都需要重新授权。
真是蛮有意思又非常实用的一个小需求,以后如果想要分享自己的程序但又不希望自己的程序被随意传播的,都可以用得上。
这里给大家简单分享一下我的实现方法,感兴趣的同学可以学起来。
如果你有其它比较好的思路,也欢迎跟我一起交流。
软件授权方案大概分成两个部分:程序本体
和 注册机
。
当用户启动程序时,程序会检验本地的 授权文件
是否合法,若验证通过,则直接进入程序,若未找到授权文件或者授权文件校验失败,则进入重新授权流程。进入授权流程时,程序先扫描本机运行环境,生成 机器码
,然后提示用户找管理员获取授权码;用户将机器码发送给管理员,管理员将机器码输入 注册机
中,生成与该机器码唯一绑定的 授权码
后,发送给用户;用户在程序中输入授权码,验证通过后正式进入程序,并在本地生成授权文件。
下面是我的软件授权方案的流程图。
以上便是我这套软件授权方案的总体思路,接下来,我会教大家如何用 python 来实现它。
实现这套授权机制,我们需要解决以下几个小问题。
带着这些问题,我们继续往下看。
要回答第一个问题,首先要搞明白,软件如何判断自己运行在哪一台机器上?
我们知道,每一台机器都会有一个唯一 Mac 地址,我们可以用它来作为机器的唯一标识。
此外为了保险,我们还可以获取机器的 CPU 序列号
、硬盘序列号
、主板序列号
等等数据,与 Mac 地址
共同作为一台机器的唯一标识。
windows 系统下,我们可以使用 wmi
的库来获取机器的硬件信息。
没有安装 wmi
库的,可以运行下面的命令行来安装。
pip install wmi
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)
import wmi
m_wmi = wmi.WMI()
for network in m_wmi.Win32_NetworkAdapterConfiguration():
mac_address = network.MacAddress
if mac_address != None:
print(mac_address)
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)
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)
使用上述方法,我们可以获取到机器的 CPU 序列号
、硬盘序列号
、主板序列号
与 Mac 地址
信息,通过这些信息,我们便可以生成唯一标识一台机器的 机器码
。
理论上,我们将这些数据直接进行字符串拼接,便可作为机器码使用,但是实际上,这样做存在一些问题。
所以我们需要对机器的这些硬件数据进行一些处理,生成一个长度适中的,既可以作为机器的唯一标识,又不会暴露机器硬件数据的机器码。
# 获取机器的 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个字符),另一方面也可以在一定程度上保护数据安全。
想要在离线的情况下实现 授权码
和 机器码
唯一绑定,意味着授权码是由机器码经过一系列复杂的加密算法处理后得到的。
授权码验证的逻辑也比较简单,大概有三种思路:
一般来讲,第一种思路实现起来会比较简单一些,因为它只需要写一套加密算法即可(软件验证部分跟授权码生成部分用的是同一套加密算法),而且无需考虑解密的问题,安全性会更高(因为可以使用不可逆的加密算法)
大概的验证逻辑如下:
# 获取机器码
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("验证失败")
如何将机器码加密生成授权码,可以使用的加密算法其实五花八门,每个人都可以自己研究一套自己独有的加密方法,尤其是不需要考虑解密,不要求算法可逆的情况下,问题就更简单了。
比如:
总之,方法是非常多样化的,只要你生成的授权码可以正常使用,并且没那么容易让别人猜出你授权码生成的规律即可。
作为示例,我演示一下我 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
通过上述加密算法,我们可以通过机器码生成授权码,并且通过一系列加密算法的组合加密,基本上很难观察出机器码和授权码之间的关系,更没办法推算出你具体用了什么加密方法。
需要说明的是,
不管使用什么算法,凡离线方式的加密必然是可以被破解的,只是破解的时间和成本问题,所以上述的加密只是提高了破解门槛,防小白不防大神。
想要万无一失,还得是在线授权验证。
核心算法搞定以后,整理一下代码就可以打包测试了。
可以使用 pyinstaller
库来把代码打包成 .exe
程序。
没有安装 pyinstaller
库的,可以运行下面的命令行来安装。
pip install pyinstaller
使用 pyinstaller
库打包的命令如下:
pyinstaller -F xxx.py
打包完成以后,会在当前目录下的 dist
文件夹中,生成 xxx.exe
可执行程序。
首次启动程序时(无授权文件),会提示输入激活码,即授权码。
随便输入错误的授权码,会验证失败,提示重新输入。
此时我们启动注册机,根据提示复制机器码 BD1F7DF8646CD3A101C3DA8610672ED1
到注册机中,生成激活码。
复制并输入激活码,此时授权验证成功,程序可以正常使用,输出了 Hello World!
字样。
后续再次启动程序时,由于已有授权文件,所以可以直接进入。
为了方便大家学习交流,我将代码整理打包上传,并附上了一个 Demo 程序。
关注公众号
机灵鹤
并回复文字授权码
,即可获取。
感兴趣的同学可以自行下载,大家一起交流学习。
当然,作为 V1.0
版本的授权码机制,其实还是有很多值得改进的地方,比如:
设置授权有效期,过期则需要重新授权
授权方式改成在线,安全性更高的同时也可以进行更加精细化的授权管理。
授权后台管理系统,更加方便地管理自己的软件授权。
…
如果后续大家有需求,我也有精力的话,可以把它做的更加完善一些。
如果文章中有哪里没有讲明白,或者讲解有误的地方,欢迎在评论区批评指正,大家一起学习交流,共同进步。
文章浏览阅读2.1k次。计算机的发展趋势,未来计算机性能应向着微型化、网络化、智能化和巨型化的方向发展。主要特点1.运算速度快:计算机内部电路组成,可以高速准确地完成各种算术运算。2.计算精确度高:科学技术的发展特别是尖端科学技术的发展,需要高度精确的计算。3.存储容量大:计算机内部的存储器具有记忆特性,可以存储大量的信息。4.自动化程度高:计算机具有存储记忆能力和逻辑判断能力,所以人们可以预先编好程序组然后纳入计算机内..._未来计算机都有哪些种类?有什么特点?
文章浏览阅读802次,点赞10次,收藏16次。需要提供前端源码,后端源码,控件源码,公司自己的项目,也有自己的产品,后续需要集成使用,提供7*24小时技术支持服务,提供文档教程,视频教程,远程技术指导,1对1技术支持服务,提供手机,微信,QQ,邮箱,企业微信等联系方式。要求支持断点续传,支持进度信息离线存储,用户可能传一半没有传完,下班了,明天上班后继续上传,电脑晚上到点需要关机,支持加密传输,支持国密加密算法SM4,要求能够在网页上面上传文件夹,文件夹里面大约有1万多个文件,有大有小,大的有1G~10G,小的有几MB,使用IIS Express。
文章浏览阅读657次,点赞12次,收藏19次。那我们该怎么做才能做到年薪60万+呢,对于程序员来说,只有不断学习,不断提升自己的实力。我之前有篇文章提到过,感兴趣的可以看看,到底要学习哪些知识才能达到年薪60万+。通过职友集数据可以查看,以北京 Android 相关岗位为例,其中 【20k-30k】 薪酬的 Android 工程师,占到了整体从业者的 30.8%!北京 Android 工程师「工资收入水平 」今天重点内容是怎么去学,怎么提高自己的技术。1.合理安排时间2.找对好的系统的学习资料3.有老师带,可以随时解决问题。
文章浏览阅读7.3k次。本教程基于Proxmox VE(PVE)7.1虚拟机环境下安装群晖,兼容这块简单说明:Intel酷睿四代以下或者志强处理器建议安装Ds3615-3617-3266等版本,四代以上可以安装918-920等版本,如果你``啥都不知道,安装Ds3615就对了。1.先删除删除local-lvm分区, 具体教程https://blog.csdn.net/u012514495/article/details/127318440。10.网络这里,因为引导包含虚拟机的驱动,所以不需要在进行额外设置,默认即可,继续下一步。_群晖系统
文章浏览阅读259次。FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输出。FreeMarker 与 Web 容器无关,即在 Web 运行时,它并不知道 Servlet 或 HTTP。它不仅可以用作表现层的实现技术,而且还可以用于生成 XML,JSP 或 Java 等。一、Freemarker 的介绍 Freemarker 是一款模板引擎,是一种基于模版生成静态文件的..._freemarker templatedirectivemodel 例子
文章浏览阅读544次。微信小程序request请求封装,session封装,会话超时处理直接上代码,代码中写了很详细的注释// 同时发送异步代码的次数let ajaxTimes = 0;export const request = (params, method) => { let header = { ...params.header, "Cookie": getApp().globalData.cookieStr, 'loc':'ajax' };//头部,小程序的头部是默认的 _微信小程序 请求封装 超时
文章浏览阅读13次。研究还发现,发作性睡病患者的家族中,常常存在多个成员患有相同的疾病,这进一步表明了遗传因素在发作性睡病的发病中的重要性。因此,对于具有发作性睡病遗传倾向的人群,应该注意保持健康的生活方式和良好的心理状态,以降低患上发作性睡病的风险。但是,需要指出的是,虽然遗传因素在发作性睡病的发病中起到了重要的作用,但并不是所有具有遗传易感性的人都会患上发作性睡病。因此,即使具有发作性睡病的遗传倾向,通过保持健康的生活方式和良好的心理状态,也可以降低患上发作性睡病的风险。
文章浏览阅读3.6k次,点赞3次,收藏10次。nodejs官方维护了一套ABI(应用二进制接口),用于完成nodejs和C++的通信。官网介绍的是C API,对应的是它的C++版本,更容易使用,本文介绍的也是这个C++的版本。通过一个示例来说明如何使用node-addon-api。_js调用c++库
文章浏览阅读1.4k次。本文将对EMQX全新的网关框架及功能使用进行详细解读,帮助读者更好地利用EMQX的多协议接入能力连接各类设备,满足更多物联网场景的数据接入需求。_emqx连接对调物联网设备
文章浏览阅读475次。python并发与网络编程Linux 操作系统及其组成1.操作系统的作用 操作系统 : 与硬件交互 应用程序 --> 请求调用操作系统功能 --> 硬件调用(cpu,内存) 操作系统(OS)是管理计算机硬件与软件资源的计算机程序,同时也是计算机系统的内核与基石。操作系统需要处理如管理与配置内存、决定系统资源供需的优先次序、控制输入设备与输出设备、操作网络与管理文件系统等基本事务。操作系统也提供一个让用户与系统交互的操作界面。2.Linux 操作系统组成一个典型的 Linu_python中for循环联网请求参数
文章浏览阅读7.1k次。自定义注解+POI实现流式数据导入,支持各数据类型转换_poi 流式处理原理
文章浏览阅读2.8k次,点赞2次,收藏5次。计算机组成原理是计算机的核心,主要包括计算机基本组件的构造、组织方式和设计思想,以及基本运算的操作原理。_指令可以表示为二进制代码串