公司的一個項目快完成了,最後要加上註冊驗證,翻了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代碼,只有靠可靠的強名稱以及數字證書來保證程序集不被修改了。