天天看點

用于C# WinForm可擴充的一套授權驗證政策[postbird_license.cs]

版權屬于: 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的一個分支版本,也是最早的是時候用到的,軟體打開後,如果沒有授權,則需要第一次授權驗證。

用于C# WinForm可擴充的一套授權驗證政策[postbird_license.cs]

隻有授權驗證通過才能使用軟體進入主要的winform。

用于C# WinForm可擴充的一套授權驗證政策[postbird_license.cs]

實作:

幾個關鍵點:

1、保證本機驗證的确定性。(本機驗證需要保留授權許可證明,不需要每次驗證授權)

2、保證授權的可靠性。

3、保證授權的内容的多變性。

授權驗證的流程:

1、判斷本機是否已經授權了,若沒有授權則進行授權。

2、輸入姓名和相關的授權碼以及驗證碼發送驗證請求。

3、server進行授權驗證的判斷。

4、記錄本機授權資訊。

5、授權結束。

一、本機授權的驗證政策(機器标記碼)

首先,擷取本機的各種碼,這一點很關鍵,在我開源的版本中,擷取了Mac位址,擷取了CPU序列号,擷取了硬碟ID,擷取了網卡硬體位址,擷取了計算機名(計算機名最後沒用,萬一改名字還要重新授權,比較麻煩,但是也是一個不錯的選擇)。

為什麼要拿到這麼多碼?

開源的版本中我是采用了txt文本的方式記錄了一個機器碼,這個機器碼是我自己生成的,生成的方式很簡單,将各種碼通過一些随機的字元進行拼接,拼接後再通過MD5加密,然後進行des的加密成一個機器碼的串,寫入文本中,并儲存在根目錄。

換句話說,這個授權檔案就是”明文”給你了,但是這個明文是根據一種規則混合了時間戳的加密串,想解出來是不可能的,因為到最後我都忘記我是怎麼加密的,看代碼才知道。

用于C# WinForm可擴充的一套授權驗證政策[postbird_license.cs]

打開這個檔案實際上就是一串賊長賊長的串,一旦你破壞了,肯定是授權失敗的,而這個串的加密是可以根據你自己的方式進行的。

(第一個串是一個機器碼,第二個串後面再說)

用于C# WinForm可擴充的一套授權驗證政策[postbird_license.cs]

開源的版本中我用了一個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位址的上線數量,最多五台):

用于C# WinForm可擴充的一套授權驗證政策[postbird_license.cs]
用于C# WinForm可擴充的一套授權驗證政策[postbird_license.cs]

四、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

用于C# WinForm可擴充的一套授權驗證政策[postbird_license.cs]

六、一些改進

開源的檔案裡面,并不是特别的完善,是以我在實際使用過程中增加了一些内容,但是我現在還在用,是以無法寫出來。

簡單說一下:

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