無法破解的軟件註冊碼算法

 


  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代碼,只有靠可靠的強名稱以及數字證書來保證程序集不被修改了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章