版權屬于: Postbird - There I am , in the world more exciting!
原文位址: http://www.ptbird.cn/winform-authority-license.html
轉載時必須以連結形式注明原始出處及本聲明。
前述:
這是一則比較蛋疼的前述。
我在http://sxw.ptbird.cn 個稅計算的授權版本中提到過,我自己搞了一個C# winform的授權驗證方案,為什麼要搞這個東西?因為我一開始寫軟體忽略了授權驗證這個東西,真的是忽略了!
因為我本身并不是做C# Winform開發的,是以我也不知道這個授權到底應該怎麼弄,網上也沒有一個适合我的說法。是以當我把軟體寫出來之後,就面臨是否要進行授權的方案,如果要進行授權,那麼應該怎麼搞。
根據我自己之前的一些積累和相關内容的查閱,最後我還是根據自己的想法,設計和實作了一套授權驗證政策。
我把它稱之為 postbird_license,典型的C/S架構實作的授權驗證服務。
描述:
其實催生它的原因很簡單,就是因為我确實不知道軟體的授權驗證方式應該怎麼處理。
我想這個問題可能不僅僅我有,或許每個winform的開發者都應該有自己的一套授權驗證方式,前提是想做授權,說句大白話就是軟體是需要付費才能用滴!
為什麼叫做可擴充軟體授權驗證解決方案,其實很簡單,因為這個授權驗證的方案,與軟體本身并沒有特别直接的聯系,即使像我一樣,一開始忘記了去設計授權,後面也是很容易和輕松地加上去。
因為我不知道是不是所有的授權都是這麼設計的,我也不知道這個叫法是否正确。(反正是自己起的名字,任性擋不住)
下面是我的debug的一個分支版本,也是最早的是時候用到的,軟體打開後,如果沒有授權,則需要第一次授權驗證。
隻有授權驗證通過才能使用軟體進入主要的winform。
實作:
幾個關鍵點:
1、保證本機驗證的确定性。(本機驗證需要保留授權許可證明,不需要每次驗證授權)
2、保證授權的可靠性。
3、保證授權的内容的多變性。
授權驗證的流程:
1、判斷本機是否已經授權了,若沒有授權則進行授權。
2、輸入姓名和相關的授權碼以及驗證碼發送驗證請求。
3、server進行授權驗證的判斷。
4、記錄本機授權資訊。
5、授權結束。
一、本機授權的驗證政策(機器标記碼)
首先,擷取本機的各種碼,這一點很關鍵,在我開源的版本中,擷取了Mac位址,擷取了CPU序列号,擷取了硬碟ID,擷取了網卡硬體位址,擷取了計算機名(計算機名最後沒用,萬一改名字還要重新授權,比較麻煩,但是也是一個不錯的選擇)。
為什麼要拿到這麼多碼?
開源的版本中我是采用了txt文本的方式記錄了一個機器碼,這個機器碼是我自己生成的,生成的方式很簡單,将各種碼通過一些随機的字元進行拼接,拼接後再通過MD5加密,然後進行des的加密成一個機器碼的串,寫入文本中,并儲存在根目錄。
換句話說,這個授權檔案就是”明文”給你了,但是這個明文是根據一種規則混合了時間戳的加密串,想解出來是不可能的,因為到最後我都忘記我是怎麼加密的,看代碼才知道。
打開這個檔案實際上就是一串賊長賊長的串,一旦你破壞了,肯定是授權失敗的,而這個串的加密是可以根據你自己的方式進行的。
(第一個串是一個機器碼,第二個串後面再說)
開源的版本中我用了一個key,而這個key是寫死的。
但是在我實際使用的版本中,這個key是通過server的請求,傳回的一個加密的串,混合在機器碼中再次進行加密。
是以注冊是必須聯網的!
實際上,機器碼最主要的作用在于,規避軟體複制黏貼使用。
軟體到了另一台電腦上,由于機器碼不比對,是以另一台電腦是不能使用的。
同樣需要注冊授權。
二、本機授權的驗證政策(yes标記碼)
yes标記碼是什麼東西?
前面說了已經把一個機器碼寫進了文檔裡,為什麼要寫這樣一個機器碼,主要就是為了驗證本機已經注冊,但是僅僅寫進去,是不能進行驗證的,因為加入了時間戳,無法驗證,除非每次聯網請求server傳回資料庫中記錄的key,但是這樣子比較麻煩,是以我就想了另外一個方式。
弄了一個yes标記碼,所謂的yes标記碼,就是根據機器碼的另一種混合加密。我們都知道des加密解密是需要key的(我還是有認真上密碼學的),而這個key和機器碼傳回的key不是一個key。是以使用一個des加密的key,再根據某種加密規則(我反正是md5和des混着用各種字元串混着用)來講機器碼進行加密,生成一個yes碼,也就是上面圖檔中第二行賊長賊長的字元串,這樣的記錄下來。
每次軟體啟動過程,隻要讀取檔案,首先驗證機器碼是否正确(判斷軟體是否是注冊在本機),将機器碼進行規則加密,驗證是否與yes碼符合一個标準即可判斷本機是否注冊。
部分代碼如下:
//驗證license中機器碼是否與本機的機器碼一緻,如果不一緻要求注冊
//如果檔案不存在也要求注冊
public bool checkCode()
{
//驗證guid和檔案是否存在
try
{
if (File.Exists(@""+""+this.file))
{
StreamReader sr = new StreamReader(this.file, Encoding.Default);
string line;
if ((line = sr.ReadLine()) != null)
{
string tmpGuid=this.Decrypt(line); //需要解密
//驗證記錄的id與目前機器是否一樣
//不一樣則需要進行注冊 如果一樣則驗證yes碼是否是開啟的
if (tmpGuid.Equals(this.guid))
{
//讀取第二行
if ((line = sr.ReadLine()) != null)
{
tmpGuid = this.Decrypt(line);//需要解密
if (tmpGuid.Equals(this.checkStatus))
{
sr.Close();
return true;
}
}
}
}
sr.Close();
}
return false;
}catch(Exception ex){
return false;
}
三、注冊授權的驗證政策(C/S架構的實作)
上面實作了本機注冊的驗證,軟體注冊後,隻要在本機使用,不需要再次進行注冊授權。
那麼如果沒有注冊授權,則需要聯機驗證(沒有做離線驗證,覺得強制要求聯機是很有必要的)。
注冊授權的過程如下:
1、使用者購買軟體
2、添加生成使用者的授權碼和驗證碼(我用了兩個碼)
3、使用者線上聯機請求注冊授權
4、server進行驗證
5、授權結束
其實注冊授權的過程并不是很複雜,關鍵問題是要開發一個server來服務軟體的授權。現在這個server我沒有開源,因為我還在用,不過很簡單就可以實作。
你可以在server上手工輸入姓名和電話,随機生成兩個串,記錄在資料庫中,然後使用者在用戶端發送post請求,server的連結隻要接收參數進行驗證就行了,用戶端實際上不需要做什麼改動。
是以我的cs中有一個屬性是 url就是請求驗證的url。
定義如下:
private string url = "http://127.0.0.1/sxwTaxCaculation/postbird_license.php/";
就是用來發送請求而已。
其實真正的驗證過程還是比較繁瑣的,因為首先你要把機器碼寫進去(注意:真正的機器碼是在注冊時候才寫入的,而驗證成功才寫入yes碼)。
這個過程沒什麼技術上的難度,可以在cs代碼中看。
server上使用者授權碼和驗證碼(我加了一個mac位址的上線數量,最多五台):
四、des加密解密
機器碼和yes碼的驗證用到了加密解密,開源的檔案主要用的是des。
des加密代碼:
// DES加密
private string Encrypt(string str)
{
try
{
DESCryptoServiceProvider descsp = new DESCryptoServiceProvider(); //執行個體化加/解密類對象
byte[] tmpKey = Encoding.Unicode.GetBytes(this.key.Substring(0,4)); //定義位元組數組,用來存儲密鑰 key必須是八位的
byte[] data = Encoding.Unicode.GetBytes(str);//定義位元組數組,用來存儲要加密的字元串
MemoryStream MStream = new MemoryStream(); //執行個體化記憶體流對象
//使用記憶體流執行個體化加密流對象
CryptoStream CStream = new CryptoStream(MStream, descsp.CreateEncryptor(tmpKey, tmpKey), CryptoStreamMode.Write);
CStream.Write(data, 0, data.Length); //向加密流中寫入資料
CStream.FlushFinalBlock(); //釋放加密流
return Convert.ToBase64String(MStream.ToArray());//傳回加密後的字元串
}catch
{
return str;
}
}
des解密代碼:
// DES解密
private string Decrypt(string str)
{
try
{
DESCryptoServiceProvider descsp = new DESCryptoServiceProvider(); //執行個體化加/解密類對象
byte[] tmpKey = Encoding.Unicode.GetBytes(this.key.Substring(0,4)); //定義位元組數組,用來存儲密鑰 key必須是八位的
byte[] data = Convert.FromBase64String(str);//定義位元組數組,用來存儲要解密的字元串
MemoryStream MStream = new MemoryStream(); //執行個體化記憶體流對象
//使用記憶體流執行個體化解密流對象
CryptoStream CStream = new CryptoStream(MStream, descsp.CreateDecryptor(tmpKey, tmpKey), CryptoStreamMode.Write);
CStream.Write(data, 0, data.Length); //向解密流中寫入資料
CStream.FlushFinalBlock(); //釋放解密流
return Encoding.Unicode.GetString(MStream.ToArray()); //傳回解密後的字元串
}
catch
{
return str;
}
}
五、說一下完整的流程
1、打開軟體,主要的winform的enable設定為false,判斷license是否正确
2、license檔案不存在則直接注冊,存在進行機器碼的比對,不比對進行注冊, 如果比對再比對yes碼,成功則進行主winform,否則注冊
3、如果需要注冊,添加使用者,生成驗證碼和授權碼。
4、使用者發送請求的時候,首先生成目前機器碼,記錄到license檔案,如果驗證成功,根據機器碼生成yes碼,再次記錄,記錄完成。
5、開放主winform
六、一些改進
開源的檔案裡面,并不是特别的完善,是以我在實際使用過程中增加了一些内容,但是我現在還在用,是以無法寫出來。
簡單說一下:
1、加密方式改變,不僅僅單純使用md5和des,用了rsa。
2、實際使用中我在license中記錄的不僅僅是兩行,還記錄了别的一些标記,方式檔案的篡改。
3、最後我沒有用txt文檔處理,使用了二進制檔案的加密使用,可以考慮一下這樣子實作,甚至可以打成dll動态庫。
4、授權驗證的伺服器也就是server可以做成使用者自己付款然後自動生成就很好了。
七、代碼
目前開源的cs托管在[email protected]和github上:
[email protected] : https://git.oschina.net/postbird/Postbird_License
github : https://github.com/postbird/Postbird_License