1 前言
目前,商用软件和共享软件绝大部份都是采用注册码授权的方式来保证软件本身不被盗用,以保证自身的利益。尽管很多常用的许多软件系统的某些版本已经被别人破解,但对于软件特殊行业而言,注册码授权的方式还是一种保护软件系统本身的一种有效的手段。
通常而言,注册码授权方式有以下几种方式:
u 安装序列号方式:这是最为常用的方式,Mircosoft提供的产品(例如:Windows系列产品、Office系列产品等等)都是采用这种方式。通过一种复杂的算法生成安装序列号,在安装过程中,安装程序对用户输入的安装序列号进行校验来验证该系统是否被合法,从而完成授权。
u 用户名+序列号方式:即软件系统的供应商给用户提供有效的用户名和序列号,用户在安装过程或启动过程中输入有效的用户名和序列号,系统通过算法校验通过后完成软件授权。
u 在线注册方式:用户安装系统后,通过网络进行注册授权。软件系统的供应商事先已经登记了用户的信息,用户在线注册时,供应商的注册系统对用户的信息进行验证。用户身份有效时,注册系统生成一个凭证信息,软件系统根据凭证信息完成授权。
u 激活码方式:用户安装系统后,软件系统会根据用户机器的关键信息(例如:MAC地址、CPU序列号、硬盘序列号等等)生成一个注册凭证(也可称为注册码),用户将这个注册凭证发送给软件供应商,供应商通过注册凭证生成一个激活码。用户输入激活码,软件系统完成授权。
不论是采用哪种方式来进行授权,理论上都是可以被破解的。只要破解者发现了软件授权机制和原理则任何保护机制都将化为乌有。因此,只能够通过选择复杂的算法和机制来增加破解者的破解难度,从而在在一定的时间内保证软件不被盗用。
RSA算法(非对称加密算法)是一个广泛用于加密和数字签名的算法,可以适用用户名+序列号、在线注册、激活码等软件保护方式
2 RSA算法介绍
RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。 RSA也是被研究得最广泛的公钥算法,从提出到现在已近二十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。
RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价,即RSA的重大缺陷是无法从理论上把握它的保密性能如何,而且密码学界多数人士倾向于因子分解不是NPC问题。
RSA的缺点主要有:
(一) 产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。
(二) 分组长度太大,为保证安全性,n 至少也要 600 bits以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。
但RSA的缺点对软件注册码而言都不是问题,因为软件注册机可以选择一个已知的素数来生成公钥和私钥。至于运算代价很高的问题而言也不是问题,因为注册凭证信息量是很小的。
RSA理论的数学基础是数论中的欧拉定理,基本原理如下:
(一) 取两个相近的大素数p、q;
(二) 计算n=p*q,z=(p-1)*(q-1);
(三) 任取一个与z互素的整数e(公因数只有1的两个数,叫做互素数);
(四) 计算满足e*d=1 mod z 的整数d;
(五) 将明文m分成字符块s加密,每个块s小于n。
(六) 加密:c=m^e mod n;解密:m=c^d mod n
(七) (n,e)和(n,d)分别称为“公开密钥”和“秘密密钥”。根据Euler定理可得:m=c^d mod n=(m^e mod n)^d mod n=m;
举例说明:
(一) 取两个素数p=11和q=13
(二) 计算n=p*q=11*13=143,z=(p-1)*(q-1)=(11-1)*(13-1)=120;
(三) 选取与z=120互素的整数e,如e=7,现可计算出满足7*d=1 mod 120的整数d=103,即:7*103=1 mod 120、7*103/120余1,
(四) 整理如下:p=11、q=13、n=143、e=7、d=103
(五) 得出公钥 (n,e)=(143,7)和私钥 (n,d)=(143,103)
以数据加密为例:
(一) 甲向乙发送机密数据信息m=85,并已知乙的公钥(n,e)=(143,7),于是可计算得出:c=m^e mod n=85^7 mod 143=123,甲将c发送至乙;
(二) 乙利用私钥(n,d)=(143,103)对c进行计算:m=c^d mod n=123^103 mod 143=85,现乙已经得到甲向其要发送的机密数据信息,而甲向乙发送信息时,甲所拥有的仅仅是乙的公钥;
由此可知,由(n,e)加密的数据只能用(n,d)解密,反之亦然,从而证明RSA加密算法是可逆的,但RSA的可逆是基于特定的数值对(即称为公钥和私钥)。
另外,RSA算法的安全性依赖于大数分解,公钥和私钥都是两个大素数(大于100个十进制位)的函数。从理论上讲,从一个密钥和密文推断出明文的难度等同于分解两个大素数的积,因此,只要选择足够大的素数、保证公钥或私钥的安全,则采用常规的破解难度是非常大的,基本上可以认定为不可能破解,由此可以认定RSA是安全的。
3 采用RSA算法实现注册码的基本原理
本文档只描述用户名+序列号、在线注册、激活码三种方式,其它方式不予考虑。
下面分别描述三种方式实现的基本原理:
3.1 用户名+序列号
1. 生成一对公钥E和私钥D(供软件注册模板和注册机使用);
2. 软件供应商编写一个注册机,通过注册机将输入的用户名与私钥D加密码生成密码C(即:注册码);软件供应商将用户名及注册码提供给用户。
3. 用户安装软件后,输入用户名和注册码,软件注册模板采用公钥E对注册码解码后生成F(即:用户名);
4. 软件注册模板比较解码后的用户名F与输入的用户名,如果相等则用户合法,完成授权,否则授权失败。
3.2 在线注册
1. 生成一对公钥E和私钥D(供注册系统和注册模板使用);
2. 软件供应商将用户的凭证信息通过私钥D加密后生成F,并存储在特定的地方,比如说:存储在注册数据库中;
3. 用户安装软件后,输入用户特征信息后,软件注册模板采用公钥E对用户特征信息加密,形式成注册凭证C,通过网络发送到供应商的注册系统中。
4. 注册系统采用私钥D加密用户注册凭证C,生成F。通过F判断用户身份的有效性;
5. 注册系统将注册验证的结果通过私钥D加密后,通过网络发送给软件系统;
6. 软件注册模板采用公钥E对验证结果进行解密,根据结果来决定是否完成授权;
3.3 激活码
1. 生成一对公钥E和私钥D(供软件注册模板和注册机使用);
2. 用户安装软件后,软件注册模板提取用户机器的特定信息(如:MAC地址、CPU序列号、硬盘序列号等等),并通过其它的编码算法(如BASE64)生成一个申请码C;
3. 用户将申请码C发给软件供应商。软件供应商通过注册机采用私钥D加密申请码C后生成激活码F。软件供应商将激活码F发给用户。
4. 用户输入激活码F,软件注册模板采用公钥E对激活码F解码后生成G(即:用户机器特征信息),然后软件注册模板提取用户机器的特定信息后进行编码。将编码的结果与G进行比较,如果相等则用户合法,完成授权,否则授权失败。
4 实现方案
4.1 整体设计
4.1.1 概述
本文档实现验证码验证功能,以DLL(动态连接库)的形式向应用程序提供验证服务。如何处理授权验证由应用程序本身来完成。
4.1.2 上下文定义 ![](https://p-blog.csdn.net/images/p_blog_csdn_net/GavinFriends/EntryImages/20090911/01.GIF)
上下文结构图
说明:
Ø 验证动态库提供密钥验证,生成、编、解码功能。
Ø 应用程序需要开发一个验证模块,通过调用验证动态库中的函数来进行验证。
Ø 验证动态库本身不会提供提示信息展现和相关界面,因此,应用程序的验证模块需要提供某些操作和提示界面(例如:注册码输入框、提示信息框等等)
模块结构图
说明:
Ø 验证接口为一组WINAPI形式的API集,提供验证相关的服务,由应用程序的验证模块调用。(C、C++、JAVA、DELPHI、VS.NET语言均可调用);
Ø 验证功能模块实现了具体的功能,由验证接口API调用,向外提供服务,其本身不向外暴露;
Ø RSA算法模块提供RSA算法实现,供验证功能模块调用;
Ø MD5算法模块提供MD5算法实现,供验证功能模块调用;
Ø BASE64算法模块提供BASE64算法实现,供验证功能模块调用;
Ø 注册表操作模块提供注册表相关操作的实现,供验证功能模块调用;
Ø 文件操作模块提供文件相关操作的实现,供验证功能模块调用
4.1.4 接口定义
4.1.4.1 IsLicensed函数
【功能说明】:判断指定应用程序是否已经被授权
【原型定义】:BOOL WINAPI IsLicensed(LPCTSTR lpAppName=NULL);
【参数说明】:lpAppName:应用程序名称,如果为空值(NULL),则验证当前应程序
【返 回 值】:TRUE:已经被授权;FALSE:未被授权
【备 注】:无
4.1.4.2 GetActivationCode函数
【功能说明】:根据特征信息获取激活码
【原型定义】:BOOL WINAPI GetActivationCode(LPCTSTR lpCharacter,
LPCTSTR lpRegisterCode
UINT32 cbSize);
【参数说明】:lpCharacter:特征信息
lpRegisterCode:加密后的激活码
cbSize: lpRegisterCode区域长度
【返 回 值】:TRUE:成功;FALSE:失败
【备 注】:该功能供软件注册机调用
4.1.4.3 GetComputerCode函数
【功能说明】:获取安装计算的特征码
【原型定义】:BOOL WINAPI GetComputerCode(LPCTSTR lpRegisterCode);
【参数说明】: lpRegisterCode:加密后的机器特征码
【返 回 值】:TRUE:成功;FALSE:失败
【备 注】:通过机器特征码调用GetActivationCode函数可取得激活码
4.1.4.4 GeneratorKeyFile函数
【功能说明】:产生密钥文件
【原型定义】:BOOL WINAPI GeneratorKeyFile(LPCTSTR lpCharacter,
LPCTSTR lpKeyFile);
【参数说明】:lpCharacter: 特征信息,如果为空(NULL),则取计算的特征信息。
lpKeyFile:保存密钥文件的名称
【返 回 值】:TRUE:成功;FALSE:成功
【备 注】:该功能供软件注册机调用
4.1.4.5 ActivationByComputer函数
【功能说明】:根据机器特征码激活系统
【原型定义】:BOOL WINAPI ActivationByComputer (LPCTSTR lpAcitveCode
,LPCTSTR lpAppName=NULL);
【参数说明】:lpAcitveCode:激活码
lpAppName:应用程序名称,如果为空值(NULL),则激活当前应程序
【返 回 值】:TRUE:激活成功;FALSE:激活失败
【备 注】:因为机器特征码可以由验证模块自动取得,因此不需要用户输入注册码
4.1.4.6 ActivationByCharacter函数
【功能说明】:根据输入的特征激活系统
【原型定义】:BOOL WINAPI ActivationByCharacter(LPCTSTR lpCharacter,
LPCTSTR lpAcitveCode,
LPCTSTR lpAppName=NULL);
【参数说明】:lpCharacter:特征信息
lpAcitveCode:激活码
lpAppName:应用程序名称,如果为空值(NULL),则激活当前应程序
【返 回 值】:TRUE:激活成功;FALSE:激活成功
【备 注】:无
4.1.4.7 ActivationByFile函数
【功能说明】:根据密钥文件激活系统
【原型定义】:BOOL WINAPI ActivationByFile(LPCTSTR lpKeyFile
LPCTSTR lpAppName=NULL);
【参数说明】:lpKeyFile:密钥文件名称
lpAppName:应用程序名称,如果为空值(NULL),则激活当前应程序
【返 回 值】:TRUE:激活成功;FALSE:激活失败
【备 注】:密钥文件不但要包括计算特征码,还要包括系统的激活码。由于密钥文件可以被多个系统使用,因此,安全性不是很高
4.1.4.8 GetEncryptKey函数
【功能说明】:获取加密所采用的KEY
【原型定义】:BOOL WINAPI GetEncryptKey(LPCTSTR lpPublicKey,
UINT32 cbSize1,
LPCTSTR lpPrivateKey
UINT32 cbSize2);
【参数说明】:lpPublicKey:公钥
cbSize1: 公钥长度
lpPrivateKey:私钥
cbSize2: 私钥长度
【返 回 值】:TRUE:成功;FALSE:成功
【备 注】:该函数在发布到应用程序中时,需要禁用
4.1.4.9 SetEncryptKey函数
【功能说明】:设置加密所采用的KEY
【原型定义】:BOOL WINAPI SetEncryptKey(LPCTSTR lpPublicKey,
UINT32 cbSize1,
LPCTSTR lpPrivateKey
UINT32 cbSize2);
【参数说明】:lpPublicKey:公钥
cbSize1: 公钥长度
lpPrivateKey:私钥
cbSize2: 私钥长度
【返 回 值】:TRUE:成功;FALSE:成功
【备 注】:该函数在发布到应用程序中时,需要禁用