版权属于: Postbird - There I am , in the world more exciting!
原文地址: http://www.ptbird.cn/winform-authority-license.html
转载时必须以链接形式注明原始出处及本声明。
这是一则比较蛋疼的前述。
我在http://sxw.ptbird.cn 个税计算的授权版本中提到过,我自己搞了一个C# winform的授权验证方案,为什么要搞这个东西?因为我一开始写软件忽略了授权验证这个东西,真的是忽略了!
因为我本身并不是做C# Winform开发的,所以我也不知道这个授权到底应该怎么弄,网上也没有一个适合我的说法。因此当我把软件写出来之后,就面临是否要进行授权的方案,如果要进行授权,那么应该怎么搞。
根据我自己之前的一些积累和相关内容的查阅,最后我还是根据自己的想法,设计和实现了一套授权验证策略。
我把它称之为 postbird_license,典型的C/S架构实现的授权验证服务。
其实催生它的原因很简单,就是因为我确实不知道软件的授权验证方式应该怎么处理。
我想这个问题可能不仅仅我有,或许每个winform的开发者都应该有自己的一套授权验证方式,前提是想做授权,说句大白话就是软件是需要付费才能用滴!
为什么叫做可扩展软件授权验证解决方案,其实很简单,因为这个授权验证的方案,与软件本身并没有特别直接的联系,即使像我一样,一开始忘记了去设计授权,后面也是很容易和轻松地加上去。
因为我不知道是不是所有的授权都是这么设计的,我也不知道这个叫法是否正确。(反正是自己起的名字,任性挡不住)
下面是我的debug的一个分支版本,也是最早的是时候用到的,软件打开后,如果没有授权,则需要第一次授权验证。
只有授权验证通过才能使用软件进入主要的winform。
几个关键点:
1、保证本机验证的确定性。(本机验证需要保留授权许可证明,不需要每次验证授权)
2、保证授权的可靠性。
3、保证授权的内容的多变性。
授权验证的流程:
1、判断本机是否已经授权了,若没有授权则进行授权。
2、输入姓名和相关的授权码以及验证码发送验证请求。
3、server进行授权验证的判断。
4、记录本机授权信息。
5、授权结束。
首先,获取本机的各种码,这一点很关键,在我开源的版本中,获取了Mac地址,获取了CPU序列号,获取了硬盘ID,获取了网卡硬件地址,获取了计算机名(计算机名最后没用,万一改名字还要重新授权,比较麻烦,但是也是一个不错的选择)。
为什么要拿到这么多码?
开源的版本中我是采用了txt文本的方式记录了一个机器码,这个机器码是我自己生成的,生成的方式很简单,将各种码通过一些随机的字符进行拼接,拼接后再通过MD5加密,然后进行des的加密成一个机器码的串,写入文本中,并保存在根目录。
换句话说,这个授权文件就是”明文”给你了,但是这个明文是根据一种规则混合了时间戳的加密串,想解出来是不可能的,因为到最后我都忘记我是怎么加密的,看代码才知道。
打开这个文件实际上就是一串贼长贼长的串,一旦你破坏了,肯定是授权失败的,而这个串的加密是可以根据你自己的方式进行的。
(第一个串是一个机器码,第二个串后面再说)
开源的版本中我用了一个key,而这个key是写死的。
但是在我实际使用的版本中,这个key是通过server的请求,返回的一个加密的串,混合在机器码中再次进行加密。
因此注册是必须联网的!
实际上,机器码最主要的作用在于,规避软件复制黏贴使用。
软件到了另一台电脑上,由于机器码不匹配,因此另一台电脑是不能使用的。
同样需要注册授权。
yes标记码是什么东西?
前面说了已经把一个机器码写进了文档里,为什么要写这样一个机器码,主要就是为了验证本机已经注册,但是仅仅写进去,是不能进行验证的,因为加入了时间戳,无法验证,除非每次联网请求server返回数据库中记录的key,但是这样子比较麻烦,因此我就想了另外一个方式。
弄了一个yes标记码,所谓的yes标记码,就是根据机器码的另一种混合加密。我们都知道des加密解密是需要key的(我还是有认真上密码学的),而这个key和机器码返回的key不是一个key。因此使用一个des加密的key,再根据某种加密规则(我反正是md5和des混着用各种字符串混着用)来讲机器码进行加密,生成一个yes码,也就是上面图片中第二行贼长贼长的字符串,这样的记录下来。
每次软件启动过程,只要读取文件,首先验证机器码是否正确(判断软件是否是注册在本机),将机器码进行规则加密,验证是否与yes码符合一个标准即可判断本机是否注册。
部分代码如下:
//验证license中机器码是否与本机的机器码一致,如果不一致要求注册
//如果文件不存在也要求注册
public bool checkCode()
{
//验证guid和文件是否存在
try
{
if (File.Exists(@""+""+this.file))
{
StreamReader sr = new StreamReader(this.file, Encoding.Default);
string line;
if ((line = sr.ReadLine()) != null)
{
string tmpGuid=this.Decrypt(line); //需要解密
//验证记录的id与当前机器是否一样
//不一样则需要进行注册 如果一样则验证yes码是否是开启的
if (tmpGuid.Equals(this.guid))
{
//读取第二行
if ((line = sr.ReadLine()) != null)
{
tmpGuid = this.Decrypt(line);//需要解密
if (tmpGuid.Equals(this.checkStatus))
{
sr.Close();
return true;
}
}
}
}
sr.Close();
}
return false;
}catch(Exception ex){
return false;
}
上面实现了本机注册的验证,软件注册后,只要在本机使用,不需要再次进行注册授权。
那么如果没有注册授权,则需要联机验证(没有做离线验证,觉得强制要求联机是很有必要的)。
注册授权的过程如下:
1、用户购买软件
2、添加生成用户的授权码和验证码(我用了两个码)
3、用户在线联机请求注册授权
4、server进行验证
5、授权结束
其实注册授权的过程并不是很复杂,关键问题是要开发一个server来服务软件的授权。现在这个server我没有开源,因为我还在用,不过很简单就可以实现。
你可以在server上手工输入姓名和电话,随机生成两个串,记录在数据库中,然后用户在客户端发送post请求,server的链接只要接收参数进行验证就行了,客户端实际上不需要做什么改动。
所以我的cs中有一个属性是 url就是请求验证的url。
定义如下:
private string url = "http://127.0.0.1/sxwTaxCaculation/postbird_license.php/";
就是用来发送请求而已。
其实真正的验证过程还是比较繁琐的,因为首先你要把机器码写进去(注意:真正的机器码是在注册时候才写入的,而验证成功才写入yes码)。
这个过程没什么技术上的难度,可以在cs代码中看。
server上用户授权码和验证码(我加了一个mac地址的上线数量,最多五台):
机器码和yes码的验证用到了加密解密,开源的文件主要用的是des。
des加密代码:
// DES加密
private string Encrypt(string str)
{
try
{
DESCryptoServiceProvider descsp = new DESCryptoServiceProvider(); //实例化加/解密类对象
byte[] tmpKey = Encoding.Unicode.GetBytes(this.key.Substring(0,4)); //定义字节数组,用来存储密钥 key必须是八位的
byte[] data = Encoding.Unicode.GetBytes(str);//定义字节数组,用来存储要加密的字符串
MemoryStream MStream = new MemoryStream(); //实例化内存流对象
//使用内存流实例化加密流对象
CryptoStream CStream = new CryptoStream(MStream, descsp.CreateEncryptor(tmpKey, tmpKey), CryptoStreamMode.Write);
CStream.Write(data, 0, data.Length); //向加密流中写入数据
CStream.FlushFinalBlock(); //释放加密流
return Convert.ToBase64String(MStream.ToArray());//返回加密后的字符串
}catch
{
return str;
}
}
des解密代码:
// DES解密
private string Decrypt(string str)
{
try
{
DESCryptoServiceProvider descsp = new DESCryptoServiceProvider(); //实例化加/解密类对象
byte[] tmpKey = Encoding.Unicode.GetBytes(this.key.Substring(0,4)); //定义字节数组,用来存储密钥 key必须是八位的
byte[] data = Convert.FromBase64String(str);//定义字节数组,用来存储要解密的字符串
MemoryStream MStream = new MemoryStream(); //实例化内存流对象
//使用内存流实例化解密流对象
CryptoStream CStream = new CryptoStream(MStream, descsp.CreateDecryptor(tmpKey, tmpKey), CryptoStreamMode.Write);
CStream.Write(data, 0, data.Length); //向解密流中写入数据
CStream.FlushFinalBlock(); //释放解密流
return Encoding.Unicode.GetString(MStream.ToArray()); //返回解密后的字符串
}
catch
{
return str;
}
}
1、打开软件,主要的winform的enable设置为false,判断license是否正确
2、license文件不存在则直接注册,存在进行机器码的匹配,不匹配进行注册, 如果匹配再匹配yes码,成功则进行主winform,否则注册
3、如果需要注册,添加用户,生成验证码和授权码。
4、用户发送请求的时候,首先生成当前机器码,记录到license文件,如果验证成功,根据机器码生成yes码,再次记录,记录完成。
5、开放主winform
开源的文件里面,并不是特别的完善,因此我在实际使用过程中增加了一些内容,但是我现在还在用,因此无法写出来。
简单说一下:
1、加密方式改变,不仅仅单纯使用md5和des,用了rsa。
2、实际使用中我在license中记录的不仅仅是两行,还记录了别的一些标记,方式文件的篡改。
3、最后我没有用txt文档处理,使用了二进制文件的加密使用,可以考虑一下这样子实现,甚至可以打成dll动态库。
4、授权验证的服务器也就是server可以做成用户自己付款然后自动生成就很好了。
目前开源的cs托管在git@osc和github上:
git@osc : https://git.oschina.net/postbird/Postbird_License
github : https://github.com/postbird/Postbird_License