共享軟體中註冊部分的簡單實現(轉)

ba發表於2007-08-15
共享軟體中註冊部分的簡單實現(轉)[@more@]目前,很多共享軟體中使用註冊碼來實現對軟體的保護。所謂註冊碼,就是一組與使用者的某些特定資訊(如使用者名稱稱、計算機硬體等等)相關的字串。由於註冊碼傳輸起來比較簡單,同時容易驗證(相對於磁碟、光碟指紋等),因此現在註冊碼的應用越來越廣泛,甚至一些商業軟體,如Windows XP也使用了類似的機制(Microsoft稱為Windows Product
Activation)。

談起註冊碼,就不能不提註冊器。註冊器是用來產生註冊碼的程式,其計算邏輯通常與受保護的應用程式一致。透過與受保護應用程式相同,或預先約定的計算邏輯得到的註冊號,將決定受保護應用程式的行為,如顯示“軟體未註冊”、禁用某些功能,或在“關於”對話方塊中顯示註冊者的姓名,等等。

其中,終端使用者透過某種方式提交其註冊資訊,例如他(或他所在的組織)的名字,甚至極端一些,提供某些可以確定某人身份的資訊,如Pentium III CPU的CPU ID,硬碟的序列號,網路卡的MAC地址等等。然後,註冊伺服器,或呼叫中心的服務人員根據使用者提供的資訊,計算一個註冊號,並告訴終端使用者。

通常,由於人工操作可能造成差錯,我們希望註冊過程由計算機自動實現。不過這就帶來了一個問題:使用者憑什麼相信我們的程式並不會洩漏他的個人隱私呢?針對這一問題,目前流行的做法是提供若干選項,其中包括電話註冊,網路註冊,以及平信註冊等等,並把程式提交的內容告知使用者。

此外,某些與使用者的電腦相關的資訊,如配置等等,不宜使用明文傳送。這一方面是由於使用者可能不願意將這些資訊透露給我們,另一方面是以明文傳送資訊可能會導致第三方(如 cracker)截獲資訊。目前比較流行的方法是把那些我們並不需要,但卻決定使用者身份的資訊用某種雜湊演算法進行編碼然後再傳送。當然,在傳送過程中我們可以使用SSL加密,或者其他一些方法來保證安全,由於與本文的主要內容關係不大,在此不贅述,讀者可參考相關書籍。

需要保密的使用者資訊→ 雜湊演算法 → 安全傳輸(如SSL) →伺服器

就筆者個人的經驗,計算註冊碼和驗證註冊碼使用不同的演算法,可以在一定程度上提高註冊過程的安全性。當然,任何安全措施都不可能保證不被解密,“世界上沒有打不開的鎖”,解密只是一個時間問題,在構造註冊碼演算法的時候,只要讓解密代價大於軟體價值即可,不必做得太複雜。

作為使用者而言,無論是用什麼註冊方式,他都不希望過於複雜。透過計算機直接註冊的方式無疑是最方便的,但很多使用者可能不願意這樣做。作為使用者來說,透過電話註冊這種方式,說出自己的註冊ID(通常包括了產品ID、使用者的名字等資訊),以及輸入註冊碼應該是各種註冊方式中最麻煩的一種。

註冊ID和註冊碼應該具有以下特點:
(1)便於辨認、輸入。註冊碼不是密碼,沒有必要是用大量的特殊符號、大小寫組合。因此,註冊碼和註冊ID中不應該包含不同大小寫的字母,以及容易混淆的數字(1-I,0-O,2-Z)。
(2)具有查錯能力。統計證明,輸入註冊碼時,錯序(如把1234輸入成1243)、擊鍵錯誤是最常見的錯誤。比較常用的方法是把註冊碼分成若干節,每節包括一個校驗碼,這樣註冊碼就具有查錯能力了。

為了體現上面的要求,我構造了一個這樣的演算法:
(1)計算輸入的使用者名稱,並按照下面的規則計算和:
設結果為a,預置為0
按順序取使用者名稱字串的每一個字元的ASCII值,乘上位號,累加到a上。
例如:
J a s o n   L i
1 2 3 4 5 6 7 8
這樣,a=(char)’J’+((char)’a’)*2+((char)’s’)*3+...

(2)將a、a²按照一定規則變換之後成為註冊字串。
實現程式如下:

// reg.cpp : Demo program for Keygen
// By Jason Li, 2001. Written for FrontFree techonology network

#include <string>
#include <iostream>

using namespace std;

typedef int BOOL;

const BOOL TRUE=(1==1);
const BOOL FALSE=!TRUE;

// Define the magic string
const string sMagic="L5WXTUYJH7VMB4GA8SFKQN9E36RPDC";

string GetRegstr(string &sName){
string sResult="FFTN-";
long lSum=0;
long lSum1;
long lChksum;

register unsigned int i;

// Calculate the registration string
for(i=0;i<sName.length();i++){
lSum += sName.at(i) * (i+1);
}
// The checksum prevents accident input
lChksum=sMagic.at(lSum%30);
sResult+=sMagic.at(lSum%30);
lSum1=lSum;
for(i=0;i<4;i++){
sResult+=(char)((lSum%10)+’0’);
lChksum+=((lSum%10)+’0’);
lSum/=10;
}
sResult+=(sMagic.at(lChksum%30));
sResult+="-";

lChksum=0;
lSum=lSum1*lSum1/3;
for(i=0;i<5;i++){
sResult+=sMagic.at(lSum%30);
lChksum+=sMagic.at(lSum%30)*((i%2)+1); // Sum even bytes twice
lSum/=7;
}
sResult+=(sMagic.at(lChksum%36));
sResult+="-";

lChksum=0;
lSum=lSum1*lSum1/5;
for(i=0;i<5;i++){
sResult+=sMagic.at(lSum%30);
lChksum+=sMagic.at(lSum%30)*((i%2)+1); // Sum even bytes twice
lSum/=11;
}
sResult+=(sMagic.at(lChksum%36));
sResult+="-";

lChksum=0;
lSum=lSum1*lSum1/7;
for(i=0;i<5;i++){
sResult+=sMagic.at(lSum%30);
lChksum+=sMagic.at(lSum%30)*((i%2)+1); // Sum even bytes twice
lSum/=17;
}
sResult+=(sMagic.at(lChksum%30));

return sResult;
}

int main(void){
string sName;
string sRegstr;

// Output the prompt for user
cout << "Registration Code Generator DEMO program version 1.00" << endl;
cout << "By Jason Li, 2001. For test purpose only." << endl;
cout << endl;

// Loop until the user name is legal to the algorithm
do{
// Get the user name
cout << "Enter the user’s name (5 chars min), followed by comma(,): ";
getline(cin, sName, ’,’);
}while(sName.length()<=5);

cout<<"User "<<sName;

sRegstr=GetRegstr(sName);

cout<<" has the registration string of "<<sRegstr;
cout<<endl;

return 0;
}

程式按ANSI C++標準編寫,在Visual C++ 6和GNU C++中執行通

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617731/viewspace-957679/,如需轉載,請註明出處,否則將追究法律責任。

相關文章