1. 程式人生 > >推薦+1置頂+1(分享、討論、實現) 通用軟體註冊功能之建立有效的軟體保護機制

推薦+1置頂+1(分享、討論、實現) 通用軟體註冊功能之建立有效的軟體保護機制

推薦+1置頂+1(分享、討論、實現)

通用軟體註冊功能之建立有效的軟體保護機制

         眾所周知,一些共享軟體往往提供給使用者的是一個功能不受限制的限時使用版,在試用期內使用者可以無限制的使用軟體的全部功能(只是可能會出現提示使用者註冊的視窗),試用期一過部分(或全部)功能失效,要想繼續使用只能向作者索取註冊碼(或註冊檔案)完成對軟體的合法註冊,註冊後的軟體將解除一切使用限制。如果您也開發出一個有價值的作品,是否也希望為自己的軟體增加一個這樣的功能呢?當前對於.NET反編譯的問題不在本文討論之內,相關文章已經很多!本文我們就一起探討軟體註冊功能的實現。

       實現軟體的註冊功能方法很多,最需要考慮的就是不能輕易的讓使用者破解,在這裡,我就談談“.NET快速開發整合框架(RDIFramework.NET)”中平臺註冊功能的實現方法。在RDIFramework.NET中,註冊功能主要方法就是對計算機唯一硬體資訊進行RSA數字簽名達到軟體註冊和保護的功能,該方法實現簡單,安全性相應較高。

       計算機唯一硬體資訊(我們知道計算機中的關鍵部件如CPU,主機板等在全球範圍內都有一個獨一無二的產品序列號,使用者通過註冊模組獲取這些產品序列號(即傳統所說的:機器嗎)並將它傳送給軟體開發商要求進行RSA資料簽名,軟體開發商獲得這些機器碼後利用手中的私鑰對這些資訊進行RSA數字簽名,生成的簽名信息(即註冊碼)發回給使用者,使用者將收到的註冊碼輸入註冊模組的註冊碼框,軟體即可利用公鑰執行簽名驗證,如果輸入的註冊碼被證明就是經過開發商數字簽名的機器碼,則完成註冊過程。

       註冊功能專案結構圖如下所示:

 

圖1 註冊功能專案結構

平臺服務端註冊碼生成主介面如下所示:

 

圖2 註冊檔案管理器

通過“註冊檔案管理器”,我們就可以根據使用者提供的資訊來生成軟體的註冊檔案。

客戶端的註冊主要就是根據我們提供的註冊檔案與公鑰,來驗證註冊檔案是否為當前客戶的有效註冊檔案,如果有效,註冊成功,無效則註冊失敗!客戶端註冊功能設計參考如下所示:

 

圖3 平臺註冊

使用者單擊“註冊”按鈕,成功註冊提示:

 

圖4註冊成功

服務端註冊碼生成核心程式碼:

一、     生成公/私鑰檔案:

 1 private void btnGenerateKey_Click(object sender, EventArgs e)
 2         {
 3             if (MessageBox.Show("確定生成生成公/私鑰對嗎(是/否)?
", "詢問資訊", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) 4 == System.Windows.Forms.DialogResult.Cancel) 5 { 6 return; 7 } 8 9 RSACryptoServiceProvider crypt = new RSACryptoServiceProvider(); 10 11 string publicKey = crypt.ToXmlString(true); 12 string privateKey = crypt.ToXmlString(false); 13 crypt.Clear(); 14 15 //生成公鑰 16 using (StreamWriter sw = new StreamWriter(KeyPath + "RDIFrameworkkey.key", false, UTF8Encoding.UTF8)) 17 { 18 sw.Write(SecretHelper.AESEncrypt(publicKey)); 19 sw.Flush(); 20 } 21 22 //生成私鑰 23 using (StreamWriter sw = new StreamWriter(KeyPath + "RDIFrameworkPrivateKey.key", false, UTF8Encoding.UTF8)) 24 { 25 sw.Write(SecretHelper.AESEncrypt(privateKey)); 26 sw.Flush(); 27 } 28 29 MessageBox.Show("成功生成公/私鑰對!","提示資訊",MessageBoxButtons.OK,MessageBoxIcon.Information); 30 }

二、     生成註冊檔案:

 1 private void btnGenerateRegisterFile_Click(object sender, EventArgs e)
 2         {
 3             if (string.IsNullOrEmpty(txtUserEmail.Text.Trim()))
 4             {
 5                 MessageBox.Show("使用者郵箱不能為空!", "提示資訊", MessageBoxButtons.OK, MessageBoxIcon.Warning);
 6                 txtUserEmail.Focus();
 7                 return;
 8             }
 9             else
10             {
11                 if (!RegexValidatorHelper.IsMatch(txtUserEmail.Text.Trim(), Pattern.EMAIL))
12                 {
13                     MessageBox.Show("郵箱格式不正確!", "提示資訊", MessageBoxButtons.OK, MessageBoxIcon.Warning);
14                     txtUserEmail.SelectAll();
15                     return;
16                 }
17             }
18 
19             if (string.IsNullOrEmpty(txtCPUSerialNo.Text.Trim()))
20             {
21                 MessageBox.Show("CPU序列號不能為空!", "提示資訊", MessageBoxButtons.OK, MessageBoxIcon.Warning);
22                 return;
23             }
24 
25             if (!string.IsNullOrEmpty(txtUseLimited.Text.Trim()))
26             {
27                 if (!RegexValidatorHelper.IsMatch(txtUseLimited.Text.Trim(), Pattern.INTEGER))
28                 {
29                     MessageBox.Show("使用次數應該為數值型!", "提示資訊", MessageBoxButtons.OK, MessageBoxIcon.Warning);
30                     txtUseLimited.SelectAll();
31                     return;
32                 }
33             }
34 
35             //讀取私鑰
36             StreamReader sr = new StreamReader(KeyPath + "RDIFrameworkPrivateKey.key", UTF8Encoding.UTF8);            
37             string keypair = sr.ReadToEnd();
38             sr.Close();
39 
40             //用私鑰引數初始化RSACryptoServiceProvider類的例項crypt。
41             RSACryptoServiceProvider crypt = new RSACryptoServiceProvider();
42 
43             crypt.FromXmlString(SecretHelper.AESDecrypt(keypair));
44 
45             UTF8Encoding enc = new UTF8Encoding();
46 
47             string trialTime = "30";//試用次數(預設:30數,0:表示永久)
48             if (!string.IsNullOrEmpty(txtUseLimited.Text.Trim()))
49             {
50                 trialTime = txtUseLimited.Text.Trim();
51             }
52             string regInfo = txtUserEmail.Text.Trim() + ";" + txtMAC.Text.Trim() + ";" + txtCPUSerialNo.Text.Trim() + ";" + trialTime;
53 
54             byte[] bytes = enc.GetBytes(regInfo);//格式:郵箱地址;MAC;CPU序列號;試用時間
55             //對使用者資訊加密
56             bytes = crypt.Encrypt(bytes, false);
57             
58             //生成註冊資料,對二進位制位元組進行Base64編碼,但採用註冊檔案的形式的進修也可以不做此轉化。
59             string encrytText = System.Convert.ToBase64String(bytes, 0, bytes.Length);
60 
61             //將註冊碼寫入檔案
62             using (StreamWriter sw = new StreamWriter(KeyPath + "RDIFramework_reg_file.lic", false, UTF8Encoding.UTF8))
63             {
64                 sw.Write(encrytText);
65                 sw.Flush();
66             }
67 
68             MessageBox.Show("註冊檔案:RDIFramework_reg_file.lic生成成功!", "提示資訊", MessageBoxButtons.OK, MessageBoxIcon.Information);         
69         }

三、     驗證註冊檔案:

 1 private void btnCheckRegistr_Click(object sender, EventArgs e)
 2         {
 3             //讀取註冊資料檔案
 4             StreamReader sr = new StreamReader(KeyPath + "RDIFramework_reg_file.lic", UTF8Encoding.UTF8);
 5             string encrytText = sr.ReadToEnd();
 6             sr.Close();
 7 
 8 
 9             //讀取公鑰
10             StreamReader srPublickey = new StreamReader(KeyPath + "RDIFrameworkkey.key", UTF8Encoding.UTF8);
11             string publicKey = srPublickey.ReadToEnd();
12             srPublickey.Close();
13 
14             //用公鑰初化始RSACryptoServiceProvider類例項crypt。
15             RSACryptoServiceProvider crypt = new RSACryptoServiceProvider();
16             crypt.FromXmlString(SecretHelper.AESDecrypt(publicKey));
17             UTF8Encoding enc = new UTF8Encoding();
18             byte[] decryptByte;
19             try
20             {
21                 byte[] newBytes;
22                 newBytes = System.Convert.FromBase64CharArray(encrytText.ToCharArray(), 0, encrytText.Length);
23                 decryptByte = crypt.Decrypt(newBytes, false);
24                 string decrypttext = enc.GetString(decryptByte);
25                 //
26                 //TODO:在此處新增驗證邏輯
27                 //
28                 MessageBox.Show(decrypttext);
29             }
30             catch(Exception ex)
31             {
32                 MessageBox.Show(ex.Message);
33             }
34         }

至此,軟體的註冊功能就完成了,當然還有其他很多方法,比如:

一、 採用加密狗的方式(最安全的方式)。

二、 線上驗證註冊資訊(使用者需能上網),這種方式也比較可靠。

三、 其他方法,歡迎大家討論。

四、  ......
作者: EricHu
出處: http://blog.csdn.net/chinahuyong
微博: 騰訊
Email: 406590790@qq.com
QQ 交流:406590790 
平臺部落格: 【CSDN】http://blog.csdn.net/chinahuyong
         【CNBLOGS】http://www.cnblogs.com/huyong
關於作者:高階工程師、資訊系統專案管理師、DBA。專注於微軟平臺專案架構、管理和企業解決方案,多年專案開發與管理經驗,曾多次組織並開發多個大型專案,精通DotNet,DB(SqlServer、Oracle等)技術。熟悉Java、Delhpi及Linux作業系統,有紮實的網路知識。在面向物件、面向服務以及資料庫領域有一定的造詣。現從事DB管理與開發、WinForm、WCF、WebService、網頁資料抓取以及ASP.NET等專案管理、開發、架構等工作。
如有問題或建議,請多多賜教!
本文版權歸作者和CNBLOGS部落格共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,如有問題,可以通過郵箱或QQ 聯絡我,非常感謝。