首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

利用 RSA 非對稱加密實作共享軟體註冊碼機制

     編輯:關於C++

前言

網路上大多數共享軟體的註冊碼(序列號)設計往往存在漏洞,容易被破解者編寫註冊機大量生成有效碼。本文介紹一種基於 RSA 非對稱加密演算法的註冊碼生成與驗證方案,若無私鑰幾乎無法構建註冊機,部分商業軟體已採用此類技術保護授權體系。

核心原理:RSA 密鑰對特性

RSA 使用一組數學關聯的金鑰:公鑰與私鑰。由公鑰推導私鑰(或反向)在計算上不可行,其安全性建立在大整數分解的困難度之上。利用此特性設計註冊流程如下:

註冊碼生成端(開發者持有私鑰)

  1. 隨機生成一組 RSA 密鑰對:公鑰 (E, N)、私鑰 (D, N),其中 N 為模數。
  2. 開發者編寫註冊機:將使用者名稱 M(經編碼為大整數)以私鑰 D 加密,得到密文 C 作為註冊碼。
    公式:C = (M ^ D) mod N
  3. 因密文可能包含不可列印字元,需經 Base64 或 uuencode 編碼轉為可顯示字串。

軟體端驗證(內嵌公鑰)

  1. 使用者輸入姓名 M 及註冊碼(經解碼還原為密文 C)。
  2. 軟體以內嵌公鑰 E 解密:M' = (C ^ E) mod N。
  3. 若 M' == M 則註冊碼合法,否則拒絕。

破解者可從程式碼中提取公鑰 E 與模數 N,但無法逆推私鑰 D,故無法偽造任意使用者的有效註冊碼。

關鍵實作細節與防護建議

1. 模數長度與大數運算庫

模數 N 過短易被分解。以當前運算能力,建議 N ≥ 512-bit(現代建議 2048-bit 以上)。此舉會增加註冊碼長度,需權衡使用者輸入便利性。實作時必須引入大數運算庫(如 Crypto++、MIRACL、GMP、OpenSSL 等)。

2. 亂數品質決定安全性

生成大質數 P、Q 時,必須使用密碼學級亂數產生器(CSPRNG),否則即使模數夠長,若亂數可預測,N 仍可能被分解。

3. 避免固定公鑰值

若改由公鑰加密、私鑰解密(即註冊機用公鑰加密,軟體用私鑰解密),則公鑰 E 不可 使用常見固定值(如 3、65537)。一旦 E 被猜測,破解者即可從軟體中提取私鑰 D 並編寫註冊機。

4. 此法僅防「註冊機」,不防「修改跳轉」

攻擊者仍可修改程式二進位碼(如將 JNE 改為 JE)繞過驗證。進階防護:以註冊碼中的部分資料加密關鍵程式碼段或資料,執行時解密,若註冊碼錯誤則解密失敗導致程式崩潰。

5. 綁定硬體資訊防止註冊碼外流

將驗證邏輯中的「使用者名稱」替換為機器唯一識別碼(CPU ID、主機板序號、MAC 位址組合等),實現「一機一碼」。注意:硬體資訊必須難以偽造且穩定,否則正版使用者換機器會失效。

6. 已知明文攻擊風險

採用上述方案後,擁有至少一組合法(姓名、註冊碼)配對的攻擊者,理論上可嘗試離線暴力破解私鑰(視模數長度而定),或直接散發該組配對。結合硬體綁定可緩解此問題。

完整程式碼範例(基於 Freelip 庫)

以下示範 64-bit RSA(僅供教學,實務請用 ≥2048-bit):

步驟 1:生成密鑰對(示範用 RSATool)

大質數 P = A57F2B33
大質數 Q = E7C441B3
模數   N = 95D49FD119EF27A9
私鑰   D = 76D2A6E2AC86CC99
公鑰   E = 65537

步驟 2:編寫註冊機(私鑰加密)

#ifndef WIN32
#define WIN32
#endif
#include "lip.h"   // Freelip 標頭
// 專案需加入 lip.c

char UserName[] = "4E6574677579";  // "Netguy" 的 ASCII 轉十六進位
char SerialNumber[256];
verylong N = 0, D = 0, M = 0, C = 0;

zhsread(UserName, &M);                    // M = 使用者名稱十六進位值
zhsread("95D49FD119EF27A9", &N);          // 載入模數
zhsread("76D2A6E2AC86CC99", &D);          // 載入私鑰
zexpmod(M, D, N, &C);                     // C = (M^D) mod N
zswrite(SerialNumber, C);                 // 輸出十進位字串作為註冊碼

步驟 3:軟體端驗證(公鑰解密)

char UserNameString[] = "4E6574677579";           // 使用者輸入姓名
char SerialNumber[]   = "1876542098762625173846272838"; // 使用者輸入註冊碼

verylong N = 0, E = 0, C = 0, UserName = 0, DecryptedUserName = 0;

zhsread(SerialNumber, &C);                // 還原密文
zhsread("95D49FD119EF27A9", &N);          // 模數
zsread("65537", &E);                      // 公鑰
zexpmod(C, E, N, &DecryptedUserName);     // M' = (C^E) mod N
zhsread(UserNameString, &UserName);       // 輸入姓名轉大數

if (zcompare(UserName, DecryptedUserName) != 0) {
    // 註冊碼錯誤
} else {
    // 註冊碼正確
}

常用大數運算庫連結

結語:RSA 非對稱機制大幅提升註冊碼抗逆向難度,配合硬體綁定、關鍵碼加密、反除錯技術,可構建相對完善的共享軟體授權體系。但請記住:沒有絕對無法破解的客戶端保護,目標是提高攻擊成本超過軟體價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved