公司的一个项目快完成了,最后要加上注册验证,翻了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代码,只有靠可靠的强名称以及数字证书来保证程序集不被修改了。

c#使用RSA进行注册码验证的更多相关文章

  1. RSA加密解密及RSA签名和验证及证书

    RSA加密解密及RSA签名和验证及证书 公钥是给别人的 发送密文使用公钥加密 验证签名使用公钥验证 私钥是自己保留的 接受密文使用私钥解密 发送签名使用私钥签名 上述过程逆转是不行的,比如使用私钥加密 ...

  2. RSA加密解密及RSA签名和验证

    原文:RSA加密解密及RSA签名和验证 1.RSA加密解密: (1)获取密钥,这里是产生密钥,实际应用中可以从各种存储介质上读取密钥 (2)加密 (3)解密2.RSA签名和验证 (1)获取密钥,这里是 ...

  3. RSA 签名、验证、加密、解密帮助类

    import java.io.IOException; import java.security.InvalidKeyException; import java.security.KeyFactor ...

  4. php中rsa加密解密验证

    RSA非对称加密,对敏感的数据传输进行数据加密.验证等.测试环境:wamp.aliyun虚拟主机(lamp)一.加密解密的第一步是生成公钥.私钥对,私钥加密的内容能通过公钥解密(反过来亦可以).下载生 ...

  5. RSA签名和验证数据

    private const string PubKey = "BgIAAACkAABSU0ExAAQAAAEAAQAxg/L6l3AyA+Zd7Hm7ESCcS4CcgY8PvwE2arRv ...

  6. go语言 RSA数字签名和验证签名

    package main import ( "crypto" "crypto/rand" "crypto/rsa" "crypto ...

  7. (转)Python rsa 签名与验证 sign and verify

    转自:http://wawehi.blog.163.com/blog/static/143780306201371361120515/ 网上一搜一大把的 python rsa 相关的东西,python ...

  8. Python 通过RSA实现license验证设备指纹与有效期

    前言 本文使用RSA非对称加密算法,了解详情请访问: RSA 非对称加密算法简述 https://blog.csdn.net/ctwy291314/article/details/88821838 P ...

  9. 【C#公共帮助类】给大家分享一些加密算法 (DES、HashCode、RSA、AES等)

    AES 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的 ...

随机推荐

  1. 02. 爬取get请求的页面数据

    目录 02. 爬取get请求的页面数据 一.urllib库 二.由易到难的爬虫程序: 02. 爬取get请求的页面数据 一.urllib库 urllib是Python自带的一个用于爬虫的库,其主要作用 ...

  2. copy contents of file with variable number in Matlab

    input : transient.case output: transient_1.case, transient_2.case, transient_3.case ... ************ ...

  3. 9.2 Socket编程

    远程管理软件和黑客软件大多依赖于Socket来实现特定功能,前几年流行的端口反弹更是把这项技术发挥到了极致. 如前所述,UDP和TCP是网络体系结构的传输层运行的两大重要协议,其中,TCP适用于对效率 ...

  4. BZOJ 4327 [JSOI2012]玄武密码 (AC自动机)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4327 题解: 做法挺显然,建出AC自动机之后在上面跑,标记所有走过的点,然后再进行递推 ...

  5. 【codeforces 515B】Drazil and His Happy Friends

    [题目链接]:http://codeforces.com/contest/515/problem/B [题意] 第i天选择第i%n个男生,第i%m个女生,让他们一起去吃饭; 只要这一对中有一个人是开心 ...

  6. [bzoj2502]清理雪道[上下界网络流]

    bzoj状态里有两种,一种时间是个位数,一种是四位数,我就是四位数的那种,,,估计都是看了hzwer.. #include <bits/stdc++.h> #define INF 0x3f ...

  7. [bzoj4282]慎二的随机数列_动态规划_贪心

    慎二的随机数列 bzoj-4282 题目大意:一个序列,序列上有一些数是给定的,而有一些位置上的数可以任意选择.问最长上升子序列. 注释:$1\le n\le 10^5$. 想法:结论:逢N必选.N是 ...

  8. spring-cloud-feign使用@RequetParam错误:QueryMap parameter must be a Map: int

    错误: QueryMap parameter must be a Map: int spring-cloud-feign处理@RequestParam和Spring MVC的不一样,Spring MV ...

  9. VC ON_CONTROL_RANGE多个控件响应一个方法

    步骤/方法 分三个步骤 在头文件里声明函数比如 afx_msg void onNum(UINT uID) 在.cpp文件里加入函数体 void CCalculatorDlg::OnNum(UINT u ...

  10. android 通用菜单条实现(一)

    一.前言介绍 直奔主题啦,非常多Android app都有菜单条.菜单条除了背景图片.图标的不同外,布局基本一致.大致能够分为三部分:菜单条的左側区域.菜单条中间区域.菜单条右側区域. 为了考虑代码的 ...