來源:Internet
作者:未知
[資料是從免費網站上擷取的,上傳在這裡,只為交流學習目的,文章原作者保留所有權力,
如本部落格的內容侵犯了你的權益,請與以下地址聯絡,本人獲知後,馬上刪除。同時本人深表歉意,並致以崇高的謝意!
erwin_609@msn.com]
網上大多數共用軟體的註冊碼(又稱為序號)的設計都不是很好,比較容易被破解者做出註冊機來。下面介紹一種利用公開金鑰演算法(又稱為非對稱演算法)RSA製作註冊碼的方法。採用這種方法,不知道密鑰的話時很難寫出註冊機來。實際上有部分軟體已經使用了這類方法。
大家都知道RSA採用一對密鑰,即公開金鑰和私密金鑰,從公開金鑰難於推出私密金鑰,反之亦然,這個難度是基於大數分解的難度。利用RSA產生共用軟體註冊碼的思路如下:
1、先隨機產生一對公開金鑰E和私密金鑰D;
2、軟體作者自己寫一個註冊機,註冊機完成的工作就是把使用者名稱M用私密金鑰D加密,密文C就是註冊碼。由於密文往往包含不可顯示字元,所以最好把密文進行編碼,變成可顯示字元,比如採用base64、uuencode編碼等。
密文C = (M ^ D) mod N
其中^表示乘冪,mod表示求餘,N為RSA的模數。
3、共用軟體將使用者輸入的註冊碼先進行解碼(如base64解碼等),得到密文,然後用公開金鑰E對密文進行解密,得到明文M',如果明文和使用者名稱相同(即滿足M' = M),則說明註冊碼正確,否則就是非法的註冊碼。破解者可以通過跟蹤你的軟體得到公開金鑰E,但無法得到私密金鑰D。
明文M' = (C ^ E) mod D
有幾點需要說明:
1、模數N太短時不安全,容易被分解。以目前的計算能力,建議N取值在512-bit以上。但這樣註冊碼的長度也變長了,可能給使用者帶來不方便。一般要採用大數運算庫來實現RSA。
2、隨機產生金鑰組時,要採用儘可能好的隨機數產生演算法,否則N還是很有可能被分解。
3、也可以在註冊機中用公開金鑰E對使用者名稱加密得到註冊碼,在軟體中對使用者輸入的註冊碼用私密金鑰D進行解密得到使用者名稱。此時公開金鑰E就不能取常用的3、65537等固定值,否則一旦被猜出E,則也可以寫出註冊機,因為此時破解者可以從你的軟體中得到私密金鑰D。
4、這種方法只是為了防止被人寫出註冊機,它無法防止通過修改程式中跳轉指令的方法來破解你的軟體。為了防止別人修改你的程式檔案,可以用註冊碼中的一部分來加密你的程式碼或資料。
5、這種方法稍加改動即可防止正版使用者散發註冊碼,即採用一機一碼的方法,將使用者名稱替換成使用者機器的硬軟體資訊即可,這個硬軟體資訊應能唯一地表示使用者的機器,否則也容易被偽造。
6、採用了上面的方法之後,只有知道至少一個合法註冊碼的人才能將程式破解。
下面舉一個例子,採用大數運算庫Freelip([url]http://www.und.nodak.edu/org/crypto/crypto/numbers/programs/freelip/freelip_1.1.tar.gz[/url])來實現RSA。該庫是用C寫的,商業使用需要許可證。
1、首先隨機產生金鑰組。可以自己編程隨機搜尋大素數。此處由於是舉例,我們採用RSATool([url]http://www.secretashell.com/TMG/RSATool2v15.zip[/url])產生64-bit RSA的參數:
大素數P = A57F2B33, 大素數Q = E7C441B3, 模數N = 95D49FD119EF27A9, 私密金鑰D = 76D2A6E2AC86CC99, 公開金鑰E = 65537
2、製作註冊機。將使用者名稱用私密金鑰D進行加密,得到的密文作為註冊碼:
首先定義宏WIN32(VC內建,但BCB中需要自己定義),然後包含標頭檔"lip.h":
#ifndef WIN32
#define WIN32
#endif
#include "lip.h"
並把"lip.c"加入到project中。
然後將使用者名稱的ASCII碼轉換成相應的十六進位串:
char UserName[] = "4E6574677579";
char SerialNumber[256];
verylong N = 0, D = 0, M = 0, C = 0; //Freelip中的大數類型為verylong。
zhsread( UserName, &M); //初始化明文M,M等於使用者名稱的十六進位表示
zhsread("95D49FD119EF27A9", &N); //初始化模數N
zhsread("76D2A6E2AC86CC99", &D); //初始化私密金鑰D
zexpmod(M, D, N, &C); //計算密文C = (M ^ D) mod N
zswrite(SerialNumber, C); //將C的十進位串表示寫入SerialNumber中,即為註冊碼
3、在軟體中判斷註冊碼。
char UserNameString[ ] = "4E6574677579"; //使用者輸入的使用者名稱
char SerialNumber[ ] = "1876542098762625173846272838"; //使用者輸入的註冊碼
verylong N = 0, E = 0, C = 0, UserName = , DecryptedUserName = 0 ;
zhsread(SerialNumber, &C); //初始化密文C
zhsread("95D49FD119EF27A9", &N); //初始化模數N
zsread("65537", &E); //初始化公開金鑰E
zexpmod(C, E, N, &DecryptedUserName); //計算明文DecryptedUserName = (C ^ E) mod N
zhsread(UserNameString, &UserName); //使用者輸入的使用者名稱
if (zcompare(UserName, DecryptedUsername))
{
//錯誤的註冊碼
}
else
{
//正確的註冊碼
}
附:常用的大數運算庫的地址(有些雖然不是專門的大數運算庫,但是帶有相關的庫)
1、Crypto++:http://www.eskimo.com/~weidai/cryptlib.html(C++)
2、MIRACL:http://indigo.ie/~mscott/(C/C++)
3、GNU MP:http://www.swox.com/gmp/(C)
4、Piologie: http://www.hipilib.de/pidownload.htm
5、cryptlib:http://www.cs.auckland.ac.nz/~pgut001/cryptlib/
6、RSAEuro:http://www.rsaeuro.com/products/RSAEuro/
7、OpenSSL:http://www.openssl.org/
9、RSARef:http://download.gale.org/rsaref20.tar.Z
10、GInt:http://triade.studentenweb.org/GInt/gint.html(Delphi)