公司的一个项目快完成了,最后要加上注册验证,翻了n多资料,终于作出来了。如今把体验说一下,之后要用的时候也好找。~~
.Net自带的类库里面有个算法。
这个算法的原理是不对称加密的原理。不对称加密原理你们基本上都了解。加密的密码(密钥)分为两个部分,公钥和私钥。经过私钥加密的密文只能经过公钥解密。根据这个特性,咱们能够发现只要开发者保存好私钥,即便算法代码被客户端破解,因客户端不知道保存在开发者处的私钥,也没法生成注册码。
如下是代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;
namespace RsaSecurity
{
public partial class Form1 : Form
{
string prikey, pubkey;
public Form1()
{
InitializeComponent();
//getKeys();
pubkey = "<RSAKeyValue><Modulus>xe3teTUwLgmbiwFJwWEQnshhKxgcasglGsfNVFTk0hdqKc9i7wb+gG7HOdPZLh65QyBcFfzdlrawwVkiPEL5kNTX1q3JW5J49mTVZqWd3w49reaLd8StHRYJdyGAL4ZovBhSTThETi+zYvgQ5SvCGkM6/xXOz+lkMaEgeFcjQQs=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
prikey = "<RSAKeyValue><Modulus>xe3teTUwLgmbiwFJwWEQnshhKxgcasglGsfNVFTk0hdqKc9i7wb+gG7HOdPZLh65QyBcFfzdlrawwVkiPEL5kNTX1q3JW5J49mTVZqWd3w49reaLd8StHRYJdyGAL4ZovBhSTThETi+zYvgQ5SvCGkM6/xXOz+lkMaEgeFcjQQs=</Modulus><Exponent>AQAB</Exponent><P>5flMAd7IrUTx92yomBdJBPDzp1Kclpaw4uXB1Ht+YXqwLW/9icI6mcv7d2O0kuVLSWj8DPZJol9V8AtvHkC3oQ==</P><Q>3FRA9UWcFrVPvGR5bewcL7YqkCMZlybV/t6nCH+gyMfbEvgk+p04F+j8WiHDykWj+BahjScjwyF5SGADbrfJKw==</Q><DP>b4WOU1XbERNfF3JM67xW/5ttPNX185zN2Ko8bbMZXWImr1IgrD5RNqXRo1rphVbGRKoxmIOSv7flr8uLrisKIQ==</DP><DQ>otSZlSq2qomgvgg7PaOLSS+F0TQ/i1emO0/tffhkqT4ah7BgE97xP6puJWZivjAteAGxrxHH+kPY0EY1AzRMNQ==</DQ><InverseQ>Sxyz0fEf5m7GrzAngLDRP/i+QDikJFfM6qPyr3Ub6Y5RRsFbeOWY1tX3jmV31zv4cgJ6donH7W2dSBPi67sSsw==</InverseQ><D>nVqofsIgSZltxTcC8fA/DFz1kxMaFHKFvSK3RKIxQC1JQ3ASkUEYN/baAElB0f6u/oTNcNWVPOqE31IDe7ErQelVc4D26RgFd5V7dSsF3nVz00s4mq1qUBnCBLPIrdb0rcQZ8FUQTsd96qW8Foave4tm8vspbM65iVUBBVdSYYE=</D></RSAKeyValue>";
}
private void button1_Click(object sender, EventArgs e)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(prikey);
// 加密对象
RSAPKCS1SignatureFormatter f = new RSAPKCS1SignatureFormatter(rsa);
f.SetHashAlgorithm("SHA1");
byte[] source = System.Text.ASCIIEncoding.ASCII.GetBytes(textBox1.Text);
SHA1Managed sha = new SHA1Managed();
byte[] result = sha.ComputeHash(source);
string s = Convert.ToBase64String(result);
MessageBox.Show("s=" + s.Length);
byte[] b = f.CreateSignature(result);
textBox2.Text = "";
textBox2.Text = Convert.ToBase64String(b);
//string s = System.Text.Encoding.Default.GetString(b, 0, 9);
}
textBox3.Text = pubkey;
textBox4.Text = prikey;
string str = textBox2.Text;
// string aa=MD5.Create(str).ToString();
}
private void button2_Click(object sender, EventArgs e)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(pubkey);
RSAPKCS1SignatureDeformatter f = new RSAPKCS1SignatureDeformatter(rsa);
f.SetHashAlgorithm("SHA1");
byte[] key = Convert.FromBase64String(textBox2.Text);
SHA1Managed sha = new SHA1Managed();
byte[] name = sha.ComputeHash(ASCIIEncoding.ASCII.GetBytes(textBox1.Text));
string s = Convert.ToBase64String(name);
if (f.VerifySignature(name, key))
MessageBox.Show("Succese!");
else
MessageBox.Show("Falied!");
}
}
void getKeys()
{
using (RSACryptoServiceProvider ras = new RSACryptoServiceProvider())
{
//公匙
pubkey = ras.ToXmlString(false);
//私匙
prikey = ras.ToXmlString(true);
}
}
}
}
这个算法就是
System.Security.Cryptography 名称空间的
RSAPKCS1SignatureFormatter 类(用来生成注册码)和
RSAPKCS1SignatureDeformatter 类(用来在客户端验证注册码)。验证过程以下:
首先,须要生成一个公钥和私钥对,固然,依靠人是没法生成的,咱们能够经过
System.Security.Cryptography 名称空间的
RSACryptoServiceProvider 类来生成公钥/私钥对。
可使用getKeys()方法得到公匙和私匙,可是若是要验证仍是要在获得公匙和私匙后保持不变,由于这个方法生成的公匙和私匙都是一直在变化的,因此要有一个肯定的公匙和私匙。
button1的Click事件中是生成注册码的过程,用
RSAPKCS1SignatureFormatter 类来生成注册码。
其中又用了sha1加密算法加密你的userId,这样可能起到的更好的保密效果。注册码验证是在button2的click事件中。
总的来讲,就是用私匙生成注册码再用公匙去验证。能够本身作个有私匙的注册机用于生成注册码,在程序中使用公匙去验证,这样整个软件的安全性就比较高了。客户端代码是没有私钥的,即便有人把程序集的代码反编译了也没有用。
不过,俺们经理以为172位的验证码实在是太长了,很差用。只有用了其中的sha1算法做了一个28位的。
等之后有时间了在写上。
Microsoft .Net的应用程序的代码文件,与Java生成的文件相似,它们都没有本地代码,而是一种相似于汇编的代码。这样,只要有合适的工具,就能够完整的把别人写出来的程序反编译成本身须要的程序文件。 我所知道的.Net下的反汇编程序是Salamander 和 Refelector 两个工具,他们均可以对.Net的程序集反编译成你须要的语言。 那么,咱们写的程序,作的项目,如何进行正版的许可证管理,有许多方法。 最好的方案,是几个方法的综合。下面我说一下单独的许可验证方法。 最简单的方法,就是使用许可存储。方法是用户输入正版的注册码,经过程序中专门的算法程序进行验算,得出的结果与事先保存在程序中的结果比对,比对一致表示输入正确。而后把结果保存在存储中,如注册表或者专门的许可文件中,程序许可经过。 这个方法使用的人/公司最多,可是缺点也是最多的,只要使用上面的工具把验算注册码的算法给弄清楚,就能够本身写一个生成序列号的注册机,这个注册方法就形同虚设了。 还有一个比较好的方法,就是仿照WindowsXP的激活机制,客户的程序自动访问互联网的一个专门设定的服务器,经过Tcp/Ip或者WebService远程访问服务器上的许可程序,许可后把结果保存在客户端计算机上。这个方法的好处是许可验证代码保存在开发者控制的计算机上,客户端没法获取验证算法,并且能够经过数据库管理用户,很是方便。 可是这个方法也有缺点,首先是可靠的Internet链接。若是要防止用户使用盗版,则必须在客户端的程序中添加一个随机访问远程许可服务器验证的功能,这样不但须要一个24小时的Internet链接,并且常常进行验证也会干扰程序的正常运行。还有就是若是有人经过研究客户端的接收返回信息的代码,弄一个虚拟的验证服务器,这个功能也会完蛋。 那么,全部的焦点都汇集在客户端的验证算法上,只要这个客户端的验证算法被人弄清楚了,整个程序的许可能够说就不存在了,因此许多开发者/开发公司费好大的力气,弄一个足够复杂的验证算法出来,用算法的复杂度来抵抗破解。可是再复杂的算法,只要有人写得出来,就有人能破解得出来,这个道理我想你们都明白。 那是否有加密算法与解密算法不一样的办法呢?有。并且.Net自带的类库里面就有这个算法。 这个算法的原理是不对称加密的原理。不对称加密原理你们基本上都了解。加密的密码(密钥)分为两个部分,公钥和私钥。经过私钥加密的密文只能经过公钥解密。根据这个特性,咱们能够发现只要开发者保存好私钥,即便算法代码被客户端破解,因客户端不知道保存在开发者处的私钥,也没法生成注册码。 这个算法就是 System.Security.Cryptography 名称空间的 RSAPKCS1SignatureFormatter 类(用来生成注册码)和 RSAPKCS1SignatureDeformatter 类(用来在客户端验证注册码)。验证过程以下: 首先,须要生成一个公钥和私钥对,固然,依靠人是没法生成的,咱们能够经过 System.Security.Cryptography 名称空间的RSACryptoServiceProvider 类来生成公钥/私钥对。 using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { // 公钥 string pubkey = rsa.ToXmlString(false); // 私钥 string prikey = rsa.ToXmlString(true); } 获取私钥之后,能够用 RSAPKCS1SignatureFormatter 类来生成注册码,代码以下(引用名称空间略) using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { rsa.FromXmlString(prikey); // 加密对象 RSAPKCS1SignatureFormatter f = new RSAPKCS1SignatureFormatter(rsa); f.SetHashAlgorithm("SHA1"); byte[] source = System.Text.ASCIIEncoding.ASCII.GetBytes(txtIn.Text); SHA1Managed sha = new SHA1Managed(); byte[] result = sha.ComputeHash(source); byte[] b = f.CreateSignature(result); msg.Text = Convert.ToBase64String(b); } 上面的代码是一个示例aspx页面的代码,页面包括一个id为msg的Label控件,一个ID为txtIn的TextBox控件,一个ID为btnOK的Button控件,上面的代码就是btnOK的事件处理程序的内容。你们能够很是清楚的看出处理流程,生成一个RsaCryptoServiceProvider类实例,而后把这个类实例的加密密钥指定为包含私钥的prikey字符串由于加密解密的公钥/私钥必须是对应的。而后获取txtIn输入的内容,生成密钥后在msg控件上显示。 下面是使用 RSAPKCS1SignatureDeformatter 类来验证输入: using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { rsa.FromXmlString(pubkey); RSAPKCS1SignatureDeformatter f = new RSAPKCS1SignatureDeformatter(rsa); f.SetHashAlgorithm("SHA1"); byte[] key = Convert.FromBase64String(txtKey.Text); SHA1Managed sha = new SHA1Managed(); byte[] name = sha.ComputeHash(ASCIIEncoding.ASCII.GetBytes(txtIn.Text)); if(f.VerifySignature(name,key)) msg.Text = "验证成功"; else msg.Text = "不成功"; } 上面的代码也很好理解,就是多了一个ID为txtKey的TextBox控件,他经过同时获取用户名/加密密钥来进行验证。重点是RSA类的FromXmlString()方法,注意上面的这个方法获取的是公钥,表示这段验证代码是保存在客户端的,客户端代码是没有私钥的,即便有人把程序集的代码反编译了也没有用。 上面两段代码须要注意的就是生成的公钥/私钥必须匹配,我使用RSA对象生成密钥对后保存成为字符串常量,就能够解决这个问题。 上面这个方法仍然没法解决客户使用ildasm反编译后暴力修改IL代码,只有靠可靠的强名称以及数字证书来保证程序集不被修改了。